How to trace this recursive program - python

I was wondering if someone would be able to tell me how this program arrives at the correct answer. I have tried to trace it and am not sure where to go because it has an or, so I am confused, how it is supposed to be traced. Thanks for any clarification.
Write a function partition that takes a list of numbers xs, a starting position i, and a desired sum s and returns True or False depending on whether it is possible to find a subsequence of the list elements starting from position i whose sum is exactly s. Note that it is always possible to produce a subsequence of elements whose sum is exactly 0, namely the empty sequence of elements.
def partition(xs,i,s):
print i,s
if i == len(xs):
return s == 0
else:
return partition(xs,i+1,s-xs[i]) or partition(xs,i+1,s)

The rcviz module is a nice tool to help to visualise recursive functions:
The edges are numbered by the order in which they were traversed by the execution. 2. The edges are colored from black to grey to indicate order of traversal : black edges first, grey edges last.
If you follow the calls which are numbered 1-11 you can see exactly what is happening, i starts at 0 then goes to 1, 2 3 and finally 4, the last value on the left is partitition([1,2,3,4],4,-2) so it returns False for s == 0.
Next we go back to where i is 2 then again 3,4 and end up with partitition([1,2,3,4],4,1) so s == 1 again is False.
Next we go from step 6 ending with partitition([1,2,3,4],4,5) where yet again s == 0 is False.
Finally in the right we go from partitition([1,2,3,4],4,7) all the way down to partitition([1,2,3,4],4,0) where s == 0 is True and the function returns True.
If you take the first four calls, you can see how the flow goes and how s is changed.
partitition([1,2,3,4],1,7) # -> xs[i] = 1 s - 1 = 7
partitition([1,2,3,4],2,5) # -> xs[i] = 2 s - 2 = 5
partitition([1,2,3,4],2,5) # -> xs[i] = 3 s - 3 = 2
partitition([1,2,3,4],2,5) # -> xs[i] = 4 s - 4 = -2
s == 0 # -> False

Maybe this version, which is logically equivalent, makes it a bit clearer. The key is that return a or b is equivalent to if a: return a else: return b.
def partition(xs,i,s):
print i,s
if i == len(xs):
# Base case: If the goal is to sum to 0, we succeed.
return s == 0
else:
# First, try including element i in our sum:
first_try = partition(xs,i+1,s-xs[i])
if first_try:
return True
else:
# If first try failed, try not including element i
second_try = partition(xs,i+1,s)
return second_try

This is an explanation of how or works in this context:
return partition(xs,i+1,s-xs[i]) or partition(xs,i+1,s)
will return partition(xs,i+1,s-xs[i]) if this expression evaluates to True. If partition(xs,i+1,s-xs[i]) evaluates to False, partition(xs,i+1,s) will be returned (regardless of whether it evaluates to True or False).
Note you can test this with the following set of simple examples:
In [1]: 1 or 2 # When both are True, the first is returned.
Out[1]: 1
In [2]: 0 or 2 # When the first is False, the second is returned.
Out[2]: 2
In [4]: 0 or False # When both are False, the second is returned.
Out[4]: False

I think it becomes a lot easier to understand if it's written with better names and no indexing:
def can_add_to(numbers, sumwanted):
if not numbers:
return sumwanted == 0
first, *rest = numbers
return can_add_to(rest, sumwanted-first) or can_add_to(rest, sumwanted)
print(can_add_to([1, 4, 9, 25], 13))
This is the same as yours, only more readable. Explanation then:
If there are no numbers, then the answer is "yes" if and only if the wanted sum is zero, and we can say that right away.
Otherwise take the first number (and the rest). You can either use it for the sum or not.
Using it: can_add_to(rest, sumwanted-first) tells you whether the remaining sum (after subtracting first) can be made from the remaining numbers.
Not using it: can_add_to(rest, sumwanted-first) tells you whether the whole sum can be made from the remaining numbers alone.
The overall answer is "yes" if and only if you can make the sum with or without first. That's why you take the two sub-answers and or them together.

Related

Creating a function that returns prime numbers under a given maximum?

Instructions are to write a function that returns all prime numbers below a certain max number. The function is_factor was already given, I wrote everything else.
When I run the code I don't get an error message or anything, it's just blank. I'm assuming there's something I'm missing but I don't know what that is.
def is_factor(d, n):
""" True if `d` is a divisor of `n` """
return n % d == 0
def return_primes(max):
result = []
i = 0
while i < max:
if is_factor == True:
return result
i += 1
You should test each i against all divisors smaller than math.sqrt(i). Use the inner loop for that. any collects the results. Don't return result right away, for you should fill it first.
def return_primes(max):
result = []
for i in range(2, max):
if not any(is_factor(j, i) for j in range(2, int(math.sqrt(i)) + 1)):
result.append(i)
return result
print(return_primes(10))
As a side note, use for and range rather than while to make less mistakes and make your code more clear.
The reason that your code is returning blank when you run it, is because you are comparing a function type to the value of True, rather than calling it.
print(is_factor)
<function is_factor at 0x7f8c80275dc0>
In other words, you are doing a comparison between the object itself rather than invoking the function.
Instead, if you wanted to call the function and check the return value from it, you would have to use parenthesis like so:
if(is_factor(a, b) == True):
or even better
if(is_factor(a, b)):
which will inherently check whether or not the function returns True without you needing to specify it.
Additionally, you are not returning anything in your code if the condition does not trigger. I recommend that you include a default return statement at the end of your code, not only within the condition itself.
Now, in terms of the solution to your overall problem and question;
"How can I write a program to calculate the prime numbers below a certain max value?"
To start, a prime number is defined by "any number greater than 1 that has only two factors, 1 and itself."
https://www.splashlearn.com/math-vocabulary/algebra/prime-number
This means that you should not include 1 in the loop, otherwise every single number is divisible by 1 and this can mess up the list you are trying to create.
My recommendation is to start counting from 2 instead, then you can add 1 as a prime number at the end of the function.
Before going over the general answer and algorithm, there are some issues in your code I'd like to address:
It is recommended to use a different name for your variable other than max, because max() is a function in python that is commonly used.
Dividing by 0 is invalid and can break the math within your program. It is a good idea to check the number you are dividing by to ensure it is not zero to make sure you do not run into math issues. Alternatively, if you start your count from 2 upwards, you won't have this issue.
Currently you are not appending anything into your results array, which means no results will be returned.
My recommendation is to add the prime number into the results array once it is found.
Right now, you return the results array as soon as you have calculated the first result. This is a problem because you are trying to capture all of the prime numbers below a specific number, and hence you need more than one result.
You can fix this by returning the results array at the end of the function, not in between, and making sure to append each of the prime numbers as you discover them.
You need to check every single number between 2 and the max number to see if it is prime. Your current code only checks the max number itself and not the numbers in between.
Now I will explain my recommended answer and the algorithm behind it;
def is_factor(d, n):
print("Checking if " + str(n) + " is divisible by " + str(d))
print(n % d == 0)
return n % d == 0
def return_primes(max_num):
result = []
for q in range(2, max_num+1):
count_number_of_trues = 0
for i in range(2, q):
if(i != q):
if(is_factor(i, q)):
print("I " + str(i) + " is a factor of Q " + str(q))
count_number_of_trues += 1
if(q not in result and count_number_of_trues == 0):
result.append(q)
result.append(1)
return sorted(result)
print(return_primes(10))
The central algorithm is that you want to start counting from 2 all the way up to your max number. This is represented by the first loop.
Then, for each of these numbers, you should check every single number from 2 up to that number to see if a divisor exists.
Then, you should count the number of times that the second number is a factor of the first number, and if you get 0 times at the end, then you know it must be a prime number.
Example:
Q=10
"Is I a factor of Q?"
I:
9 - False
8 - False
7 - False
6 - False
5 - True
4 - False
3 - False
2 - True
So for the number 10, we can see that there are 2 factors, 5 and 2 (technically 3 if you include 1, but that is saved for later).
Thus, because 10 has 2 factors [excluding 1] it cannot be prime.
Now let's use 7 as the next example.
Example:
Q=7
"Is I a factor of Q?"
I:
6 - False
5 - False
4 - False
3 - False
2 - False
Notice how every number before 7 all the way down to 2 is NOT a factor, hence 7 is prime.
So all you need to do is loop through every number from 2 to your max number, then within another loop, loop through every number from 2 up to that current number.
Then count the total number of factors, and if the count is equal to 0, then you know the number must be prime.
Some additional recommendations:
although while loops will do the same thing as for loops, for loops are often more convenient to use in python because they initialize the counts for you and can save you some lines of code. Also, for loops will take care of the incrementing process for you so there is no risk of forgetting.
I recommend sorting the list when you return it, it looks nicer that way.
Before adding the prime factor into your results list, check to see if it is already in the list so you don't run into a scenario where multiples of the same number is added (like [2,2,2] for example)
Please note that there are many different ways to implement this, and my example is but one of many possible answers.

foobar please-pass-the-coded-messages hidden test case not passing

I have been attempting google foobar and in the second level i got the task named please-pass-the-coded-messages. below is the task
==============================
You need to pass a message to the bunny workers, but to avoid detection, the code you agreed to use is... obscure, to say the least. The bunnies are given food on standard-issue plates that are stamped with the numbers 0-9 for easier sorting, and you need to combine sets of plates to create the numbers in the code. The signal that a number is part of the code is that it is divisible by 3. You can do smaller numbers like 15 and 45 easily, but bigger numbers like 144 and 414 are a little trickier. Write a program to help yourself quickly create large numbers for use in the code, given a limited number of plates to work with.
You have L, a list containing some digits (0 to 9). Write a function solution(L) which finds the largest number that can be made from some or all of these digits and is divisible by 3. If it is not possible to make such a number, return 0 as the solution. L will contain anywhere from 1 to 9 digits. The same digit may appear multiple times in the list, but each element in the list may only be used once.
Languages
=========
To provide a Java solution, edit Solution.java
To provide a Python solution, edit solution.py
Test cases
==========
Your code should pass the following test cases.
Note that it may also be run against hidden test cases not shown here.
-- Java cases --
Input:
Solution.solution({3, 1, 4, 1})
Output:
4311
Input:
Solution.solution({3, 1, 4, 1, 5, 9})
Output:
94311
-- Python cases --
Input:
solution.solution([3, 1, 4, 1])
Output:
4311
Input:
solution.solution([3, 1, 4, 1, 5, 9])
Output:
94311
Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.
i have tried a solution which is working very correct in my ide(note i wanted a solution without any library)
def solution(l):
# Your code here
if (len(l) == 1 and l[0] % 3 != 0) or (len(l) == 0):
return 0
number = formGreatestNumber(l)
remainder = number % 3
if remainder == 0:
result = formGreatestNumber(l)
return result
result = removeUnwanted(l, remainder)
return result
def formGreatestNumber(li):
li.sort(reverse=True) # descending order
li = [str(d) for d in li] # each digit in string
number = 0
if len(li) > 0:
number = int("".join(li)) # result
return number
def removeUnwanted(l, remainder):
possibleRemovals = [i for i in l if i % 3 == remainder]
if len(possibleRemovals) > 0:
l.remove(min(possibleRemovals))
result = formGreatestNumber(l)
return result
pairs = checkForTwo(l, remainder)
if len(pairs) > 0:
for ind in pairs:
l.remove(ind)
result = formGreatestNumber(l)
return result
else:
divisibleDigits = [d for d in l if d % 3 == 0]
if len(divisibleDigits) > 0:
result = formGreatestNumber(divisibleDigits)
return result
else:
return 0
def checkForTwo(l, remainder): # check of (sum of any two pairs - remainder) is divisible by 3
result = []
for i in range(len(l)):
for j in range(i+1, len(l)):
if ((l[i]+l[j])-remainder) % 3 == 0:
result.append(l[i])
result.append(l[j])
return result
return []
print(solution([]))
print(solution([1]))
print(solution([9]))
print(solution([3, 1, 4, 1, 9, 2, 5, 7]))
however it is on verifying showing-
Verifying solution...
Test 1 passed!
Test 2 passed!
Test 3 failed [Hidden]
Test 4 passed! [Hidden]
Test 5 passed! [Hidden]
so where is the error i am not noticing and is there any other way without any library like itertools?
I won't give away the code and spoil the fun for you, I'll perhaps try to explain the intuition.
About your code, I think the (2nd part of) the function removeUnwanted() is problematic here.
Let's see.
So first off, you'd arrange the input digits into a single number, in order from largest to smallest, which you've already done.
Then if the number formed isn't divisible by 3, try removing the smallest digit.
If that doesn't work, reinsert the smallest digit and remove the 2nd smallest digit, and so on.
Once you're done with removing all possible digits one at a time, try removing digits two at a time, starting with the two smallest.
If any of these result in a number that is divisible by 3, you're done.
Observe that you'll never need to remove more than 2 digits for this problem. The only way it's impossible to form the required number is if there are 2 or lesser digits and they are both either in the set {1,4,7} or {2,5,8}.
Edit: More about your code -
The initial part of your removeUnwanted() looks okay where you check if there's a single digit in the number which can be removed, removing the minimum from the choice of single digits and getting the answer.
I reckon the problem lies in your function checkForTwo(), which you call subsequently in removeUnwanted.
When you're passing the list to checkForTwo(), observe that the list is actually sorted in the decreasing order. This is because li.sort(reverse=True) in your function formGreatestNumber() sorted the list in place, which means the content of list l was sorted in descending order too.
And then in checkForTwo(), you try to find a pair that satisfies the required condition, but you're looping from the biggest 2 pairs that can possibly be removed. i starts from 0 and j starts from i+1 which is 1, and since your list is in descending order, you're trying to remove the biggest 2 elements possible.
A quick fix would be to sort the list in ascending order and then proceed further iterate through the list in reverse order, because since the list is sorted in descending order already, reverse iteration gives you the list in ascending order and saves us from re-sorting which would normally cost an additional O(NlogN) time.

Return true if a binary number either contains all zero or all ones on a single flip.(Python)

I got a program where any binary number is considered and with 1 flip of either 0 or 1, if we get all 0s or all 1s, then it returns true else it will return false.
For e.g. 110 on 1 flip of element 0 returns 111 and it is printed as true.
111 is a binary number which on one flip, is printed as false.
Any possible solution of how to solve it?
Looking forward to the best possible solutions. Appreciate if the solution is written using Python.
This is what i had actually done.
def binary(num, length = 4):
return format(num, '#0{}b'.format(length + 2)).replace('0b', '')
n = binary(125)
n.count('0')
n.count('1')
if (n.count('0') == 1) or (n.count('1') == 1):
return true
Actually I had no idea of how to flip it.
So you need to determine whether binary representation of given number contains only one "one" or only one "zero"? There is bit trick to find numbers with single bit set:
if (x == 0)
return false
if (x & (x - 1) == 0
return true
Explanation: if number looks like b00001000, then decrement gives b00000111 and binary AND leads to zero result
For checking single-zero numbers just invert them
if there is no ~ operator (binary NOT) in Python, you can invert all bits of number with
x_inversion = -(x+1)
You can loop over the values from 0 to log(x) where x is your output and xor with 2x which is 100000... Then you just check, whether what you got is 0 or 2x+1-1. It should work fine.
def g(x):
for i in range(int(log(x)/log(2))):
if x ^ 2 ** i == 0 or x ^ 2 ** i == 2 ** int(log(x)/log(2) + 1) - 1:
return True
return False
Another solution is to sort the binary interpretation of the number and check, whether these is only one 1 or only one 0. The lambda function written below does exactly that. Since bin() returns binary 0b followed by the binary interpretation of the number I get rid of it and then, remove all 0 to check whether there only one 1, the second part checks the opposite.
f = lambda x: len(str(bin(x))[2:].replace('0','')) == 1 or len(str(bin(x))[2:].replace('1','')) == 1
If x is the binary interpretation of the number, you should use this:
f = lambda x: len(x.replace('0','')) == 1 or len(x.replace('1','')) == 1
Assume that the flip can apply to any bit of the number, you can just count the occurrence of 1 or 0. If either result returns 1, then the answer is true, otherwise the answer is false:
def one_flip(i):
# i should be integer, so convert it to string using bin() and get the result excluding the '0b'
s = bin(i)[2:]
return s.count('0') == 1 or s.count('1') == 1
Just for laughs - with some bitwise manipulations:
>>> def single_flip(n):
... return any(x and not x & (x - 1) for x in [n, n^2**n.bit_length()-1])])
...
>>> single_flip(0b1110111), single_flip(0b1010111), single_flip(0b0001000)
(True, False, True)
This just tests whether the number or its bitwise complement (not 2's complement) are a factor of 2.
One possible solution:
Get first digit to check against all the others, convert to stirng, because integer is not iterable
first = str(number)[0]
Loop over all of them, return True if we go through the loop, false if we find a digit that doesn't match
for digit in str(number):
if digit == first:
continue
else:
return False
return True

Is there a better way to write the following method in python?

I am writing a small program, in python, which will find a lone missing element from an arithmetic progression (where the starting element could be both positive and negative and the series could be ascending or descending).
so for example: if the input is 1 3 5 9 11, then the function should return 7 as this is the lone missing element in the above AP series.
The input format: the input elements are separated by 1 white space and not commas as is commonly done.
Here is the code:
def find_missing_elm_ap_series(n, series):
ap = series
ap = ap.split(' ')
ap = [int(i) for i in ap]
cd = []
for i in range(n-1):
cd.append(ap[i+1]-ap[i])
common_diff = 0
if len(set(cd)) == 1:
print 'The series is complete'
return series
else:
cd = [abs(i) for i in cd]
common_diff = min(cd)
if ap[0] > ap[1]:
common_diff = (-1)*common_diff
new_ap = []
for i in range(n+1):
new_ap.append(ap[0] + i*common_diff)
missing_element = set(new_ap).difference(set(ap))
return missing_element
where n is the length of the series provided (the series with the missing element:5 in the above example).
I am sure there are other shorter and more elegant way of writing this code in python. Can anybody help ?
Thanks
BTW: i am learning python by myself and hence the question.
Based on the fact that if an element is missing it is exactly expected-sum(series) - actual-sum(series). The expected sum for a series with n elements starting at a and ending at b is (a+b)*n/2. The rest is Python:
def find_missing(series):
A = map(int, series.split(' '))
a, b, n, sumA = A[0], A[-1], len(A), sum(A)
if (a+b)*n/2 == sumA:
return None #no element missing
return (a+b)*(n+1)/2-sumA
print find_missing("1 3 5 9") #7
print find_missing("-1 1 3 5 9") #7
print find_missing("9 6 0") #3
print find_missing("1 2 3") #None
print find_missing("-3 1 3 5") #-1
Well... You can do simpler, but it would completely change your algorithm.
First, you can prove that the step for the arithmetic progression is ap[1] - ap[0], unless ap[2] - ap[1] is lower in magnitude than it, in which case the missing element is between terms 0 and 1. (This is true as there is a single missing element.)
Then you can just take ap[0] + n * step and print the first one that doesn't match.
Here is the source code (also implementing some minor shortcuts, such as grouping your first three lines into one):
def find_missing_elm_ap_series(n, series):
ap = [int(i) for i in series.split(' ')]
step = ap[1] - ap[0]
if (abs(ap[2] - ap[1]) <= abs(step)): # Check missing elt is not between 0 and 1
return ap[0] + ap[2] - ap[1]
for (i, val) in zip(range(len(ap)), ap): # And check position of missing element
if ap[0] + i * step != val:
return ap[0] + i * step
return series # missing element not found
The code appears to be working. There is perhaps a slightly easier way to get it done. This is due to the fact that you don't have to attempt to look through all of the values to get the common difference. The following code simply looks at the difference between the 1st and 2nd as well as the last and second last.
This works in the event that only a single value is missing (and the length of the list is at least 3). As the min difference between the values will provide you the common difference.
def find_missing(prog):
# First we cast them to numbers.
items = [int(x) for x in prog.split()]
#Then we compare the first and second
first_to_second = items[1] - items[0]
#then we compare the last to second last
last_to_second_last = items[-1] - items[-2]
#Now we have to care about which one is closes
# to zero
if abs(first_to_second) < abs(last_to_second_last):
change = first_to_second
else:
change = last_to_second_last
#Iterate through the list. As soon as we find a gap
#that is larger than change, we fill in and return
for i in range(1, len(items)):
comp = items[i] - items[i-1]
if comp != change:
return items[i-1] + change
#There was no gap
return None
print(find_missing("1 3 5 9")) #7
print(find_missing("-1 1 3 5 9")) #7
print(find_missing("9 6 0")) #3
print(find_missing("1 2 3")) #None
The previous code shows this example. First of all attempting to find change between each of the values of the list. Then iterating till the change is missed, and returning the value that has been expected.
Here's the way I thought about it: find the position of the maximum difference between the elements of the array; then regenerate the expected number in the sequence from the other differences (which should be all the same and the minimum number in the differences list):
def find_missing(a):
d = [a[i+1] - a[i] for i in range(len(a)-1)]
i = d.index(max(d))
x = min(d)
return a[0] + (i+1)*x
print find_missing([1,3,5,9,11])
7
print find_missing([1,5,7,9,11])
3
Here are some ideas:
Passing the length of the series seems like a bad idea. The function can more easily calculate the length
There is no reason to assign series to ap, just do a function using series and assign the result to ap
When splitting the string, don't give the sep argument. If you don't give the argument, then consecutive white space will also be removed and leading and trailing white space will also be ignored. This is more friendly on the format of the data.
I've combined a few operations. For example the split and the list comprehension converting to integer make sense to group together. There is also no need to create cd as a list and then convert that to a set. Just build it as a set to start with.
I don't like that the function returns the original series in the case of no missing element. The value None would be more in keeping with the name of the function.
Your original function returned a one item set as the result. That seems odd, so I've used pop() to extract that item and return just the missing element.
The last item was more of an experiment with combining all of the code at the bottom into a single statement. Don't know if it is better, but it's something to think about. I built a set with all the correct numbers and a set with the given numbers and then subtracted them and returned the number that was missing.
Here's the code that I came up with:
def find_missing_elm_ap_series(series):
ap = [int(i) for i in series.split()]
n = len(ap)
cd = {ap[i+1]-ap[i] for i in range(n-1)}
if len(cd) == 1:
print 'The series is complete'
return None
else:
common_diff = min([abs(i) for i in cd])
if ap[0] > ap[1]:
common_diff = (-1)*common_diff
return set(range(ap[0],ap[0]+common_diff*n,common_diff)).difference(set(ap)).pop()
Assuming the first & last items are not missing, we can also make use of range() or xrange() with the step of the common difference, getting rid of the n altogether, it can also return more than 1 missing item (although not reliably depending on number of items missing):
In [13]: def find_missing_elm(series):
ap = map(int, series.split())
cd = map(lambda x: x[1]-x[0], zip(ap[:-1], ap[1:]))
if len(set(cd)) == 1:
print 'complete series'
return ap
mcd = min(cd) if ap[0] < ap[1] else max(cd)
sap = set(ap)
return filter(lambda x: x not in sap, xrange(ap[0], ap[-1], mcd))
....:
In [14]: find_missing_elm('1 3 5 9 11 15')
Out[14]: [7, 13]
In [15]: find_missing_elm('15 11 9 5 3 1')
Out[15]: [13, 7]

Recursive binary search in Python

I am trying to understand this function with little to no avail. I completely understand what a binary search is but am only new to the concept of recursion but do have a slight grasp on it. I don't really understand what the default values of low and high would be when first calling the function. As of right now I am just including the search space I know the number is in, but what if I don't or I am not sure of the list length? Otherwise, I understand the recursion process going on here as well as the need for low and high being arguments. The function below is provided in the notes by an online course I am taking; however, it wasn't explained in the lecture and contains no docstrings or references about it.
def bSearch(L, e, low, high):
if high - low < 2:
return L[low] == e or L[high] == e
mid = low + int((high-low)/2)
if L[mid] == e:
return True
if L[mid] > e:
return bSearch(L, e, low, mid-1)
else:
return bSearch(L, e, mid+1, high)
L = [1,3,6,15,34,84,78,256]
print bSearch(L, 15, 4, 8)
print bSearch(L, 84, 0, 6)
Output:
False
True
High and low appear to be indices for which part of the list to search.
In the first example, 15 has an index of 3, so specifying a lower index of 4 means the 15 isn't included in the search space. In the second example, 84 has an index of 5, so it is included in the search space spanning indices 0 and 6.
These indices are also inclusive. If the second example were:
print bSearch(L, 84, 0, 5)
the answer would be:
True
If you want to search the entire list, you can simply do:
print bSearch(L, 84, 0, len(L) - 1)
where the - 1 is necessary because the search function is inclusive.
Binary search .
bsearch(list , element to be found , start index , end index).
start index can be taken as 0 at the start of the function
and last index can be taken as len(list)-1
As in question for bsearch(L,15 , 4 , 8 ).
U are searching only between 5th and 9th element where the number is not present.
In the second function call u are searching between first element and 5 th element where a number present.
U can call this function as bsearch(L , 15 ,0 , len(L) - 1) for any other number.
Hope this helps.
low and high specify the indices of L where the algorithm must search. In the first example, 15 has the index 3. This is not in the interval [4,8] so it will return false. In the second example the index of 84 in L is 5, this is in the interval [0,6] so this will return True.
If the number you are searching for is not in L this method will return False. Why? Because you end up in the base case of if (high-low) < 2. In this case there will be checked against L[high] or L[low] being equal to the number you are searching for. If both are not the case, it returns False. This is the definition of the logical or.
False or False = False
False or True = True
True or False = True
True or True = True
If you are not sure about the list length, this will produce an error if the high or low value you provide are not in the range of L. You can add an extra condition so this can not happen, but I think that is out of the scope of that lesson. :)

Categories

Resources