list = [27 , 39 , 56, 73, 3, 43, 15, 98, 21 , 84]
found = False
searchFailed = False
first = 0
last = len(list) - 1
searchValue = int(input("Which number are you looking for? "))
while not found and not searchFailed:
mid = (first + last) // 2
if list[mid] == searchValue:
found = True
else:
if first >= last :
searchFailed = True
else:
if list[mid] > searchValue:
last = mid - 1
else:
last = mid + 1
if found:
print("Your number was found at location", mid)
else:
print("The number does not exist within the list")
The code runs properly when I execute it while searching for 27 (the first number), but any other number just results in an infinite loop.
I believe the loop runs smoothly on the first iteration since if I change the value of first to 1, the code correctly finds the position of 39 but repeats the infinite loop error with all the other numbers after that (while 27 "does not exist within the loop" which makes sense). So I suppose the value of mid is not getting updated properly.
Several points to cover here. First, a binary search needs sorted data in order to work. As your list is not sorted, weirdness and hilarity may ensue :-)
Consider, for example, the unsorted [27 , 39 , 56, 73, 3, 43, 15, 98, 21] when you're looking for 39.
The first midpoint is at value 3 so a binary search will discard the left half entirely (including the 3) since it expects 39to be to the right of that3. Hence it will never find 39`, despite the fact it's in the list.
If your list is unsorted, you're basically stuck with a sequential search.
Second, you should be changing first or last depending on the comparison. You change last in both cases, which won't end well.
Third, it's not usually a good idea to use standard data type names or functions as variable names. Because Python treats classes and functions as first-class objects, you can get into a situation where your bindings break things:
>>> a_tuple = (1, 2) ; a_tuple
(1, 2)
>>> list(a_tuple) # Works.
[1, 2]
>>> list = list(a_tuple) ; list # Works, unintended consequences.
[1, 2]
>>> another_list = list(a_tuple) # No longer works.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not callable
Covering those issues, your code would look something like this (slightly reorganised in the process):
my_list = [3, 15, 21, 27, 39, 43, 56, 73, 84, 98]
found = False
first, last = 0, len(my_list) - 1
searchValue = int(input("Which number are you looking for? "))
while not found:
if first > last:
break
mid = (first + last) // 2
if my_list[mid] == searchValue:
found = True
else:
if my_list[mid] > searchValue:
last = mid - 1
else:
first = mid + 1
if found:
print("Your number was found at location", mid)
else:
print("The number does not exist within the list")
That works, according to the following transcript:
pax> for i in {1..6}; do echo; python prog.py; done
Which number are you looking for? 3
Your number was found at location 0
Which number are you looking for? 39
Your number was found at location 4
Which number are you looking for? 98
Your number was found at location 9
Which number are you looking for? 1
The number does not exist within the list
Which number are you looking for? 40
The number does not exist within the list
Which number are you looking for? 99
The number does not exist within the list
First of all, do not use any reserved word (here list) to name your variables. Secondly, you have a logical error in the following lines:
if list[mid] > searchValue:
last = mid - 1
else:
last = mid + 1
In the last line of the above snippet, it should be first = mid + 1
There are very good answers to this question, also you can consider this simpler version adapted to your case:
my_list = [3, 15, 21, 27, 39, 43, 56, 73, 84, 98] # sorted!
left, right = 0, len(my_list) # [left, right)
search_value = int(input("Which number are you looking for? "))
while left + 1 < right:
mid = (left + right) // 2
if my_list[mid] <= search_value:
left = mid
else:
right = mid
if my_list[left] == search_value: # found!
print("Your number was found at location", left)
else:
print("The number does not exist within the list")
The problem with your function is that in Binary Search the array or the list needs to be SORTED because it's one of the most important principal of binary search, i made same function working correctly for you
#low is the first index and high is the last index, val is the value to find, list_ is the list, you can leave low as it is
def binary_search(list_: list, val,high: int, low: int = 0):
mid = (low+high)//2
if list_[mid] == val:
return mid
elif list_[mid] <= val:
return binary_search(list_, val, high+1)
elif list_[mid] >= val:
return binary_search(list_, val, high, low-1)
and now here's the output
>>> binary_search(list_, 21, len(list_)-1)
>>> 2
what will happen here is that first it will calculate the middle index of the list, which i think of your list is 5, then it will check whether the middle value is equal to the value given to search, and then return the mid index, and if the mid index is smaller than the value, then we will tell it to add one to high index, and we did the comparison with index and value because as i told you, list needs to be sorted and this means if index is greater or equal to the mid index then the value is also surely greater than the middle value, so now what we will do is that we will call the same function again but this time with a higher high which will increase the mid point and if this time middle index is equal to value, then its gonna return the value and going to do this untill mid is equal to value, and in the last elif it says if middle value is greater than value, we will call same function again but lower the low i.e which is 0 and now -1, which will reduce the mid point and this whole process will continue untill mid is equal to value
Related
I'm working through the Codility problems and I have gotten the first one almost correct. The task is to write a function which returns the longest binary gap (a sequence of 0s in between 1s) in a binary number. I have gotten all of the test numbers correct apart from 9, which should be 2 (its binary representation is 1001) but which my function returns as 0. I can't seem to figure out why.
My function is as follows:
def Solution(N):
x = bin(N)[2:]
x_string = str(x)
y = (len(x_string))
count = 0
max = 0
for index, item in enumerate(x_string):
if item == "1":
count = 0
elif item == "0" and x_string[index + 1:y-1] != "0"*(y -1 - (index + 1)):
count = count + 1
if count > max:
max = count
print(max)
The complicated indexing and second condition in the elif statement is so that when a 0 is not contained between two 1s then it isn't recognised as the beginning of a binary gap e.g. when the for loop looks at the second character in bin(16) = 10000, it doesn't set count to 1 because all of the remaining characters in the string are also zero.
Simple solution
x_string[index + 1:y-1] != "0"
this bit wants to take a look at the whole string that's left, but the end argument isn't inclusive,it's exluded, so if string length = 4; string[0:4] is the whole string.
source: https://docs.python.org/3/tutorial/introduction.html
-Sam
I am trying to write a function which prints the minimum number of steps involved to make starting number to target number with multiply by 2 and subtract by 1.
However, I am getting the error:
RecursionError: maximum recursion depth exceeded in comparison
Here's the code I've written:
def no_steps(start,target,sofar):
if start == target:
return sofar
elif start < target and start > 0:
no_steps(start*2,target,sofar+'*2 ')
no_steps(start-1,target,sofar+'-1 ')
print(no_steps(2,6,''))
May I know what am I doing wrong and is there any issue with the code?
My interpretation is: starting from 2 (start), which sequence of multiplications by 2 and subtractions by 1 will lead to 6 (target) with the least amount of such operations, meaning not exactly always in that order.
On the one side you have a recursion prob (which is what you see in your output) due to missing implementation of correct return statements. On the other, there is also some logic missing to achieve the least amount of computation steps. My combined solution (for the recursion and the minimum num of steps) would be:
def no_steps(start, target, sofar):
if start == target:
return sofar
if 0 < start and 0 < target:
if (target % 2 == 0) and target > start:
return no_steps(start, target // 2, '*2 ' + sofar)
else:
return no_steps(start, target + 1, '-1 ' + sofar)
return sofar
no_steps(1, 6, '')
'*2 *2 -1 *2 '
no_steps(2, 6, '')
'*2 -1 *2 '
no_steps(3, 6, '')
'*2 '
no_steps(4, 6, '')
'-1 *2 '
no_steps(5, 6, '')
'-1 -1 *2 '
no_steps(6, 6, '')
''
no_steps(7, 6, '')
'-1 '
no_steps(2, 17, '')
'*2 -1 *2 -1 *2 -1 *2 -1 '
EDIT: fixed the previously flawed logic based on the answer by PabloRuiz.
Don't use recursion for this problem, I came up with a much better solution reversing the problem:
def no_steps(start, target, sofar=''):
while target != start:
if target%2 == 0 and target > start:
target //= 2
sofar = '*2' + sofar
else:
target +=1
sofar = '-1' + sofar
print(sofar)
no_steps(2, 17, '')
Note that it assumes that target is bigger than start, if is not just change the order of them to be so.
PD from here a bad answer, but still the first one I posted:
You need to stop the recursion, you can do something like:
def no_steps(start,target, path='', it=0):
if it < 10 and not reached:
it+=1
if start == target:
print(f'REACHED! in {it} iterations with {path}')
elif start < 2*target and start > 0:
no_steps(start*2,target, path=path+'*2', it=it)
no_steps(start-1,target, path=path+'-2', it=it)
else:
print('Start going beyond target')
no_steps(2,6)
You can also add an infamous global variable to stop other branches to continue growing, or just design another algorithm.
You make a common mistake with recursion, i.e you assume that return will collapse all the calls in-between original call and the one that returns something - it won't.
Let's say you run your program for start = 3 and target = 6. no_steps(start*2,target, path=path+'*2', it=it) will return a final result - back to the start = 3 call. And then you ignore this result and call no_steps(start-1,target, path=path+'-2', it=it). Which will in turn call your function with start = 4 and 1 and so forth until infinity (or recursion limit, hence the error). Once you have some result, you need to return it all the way up to the original call.
Another problem in your logic is you want to check all the possible options but have no way of catching an infinite loop like 2->4->3->2->4...
I am trying to make a code that produces numbers according to the following formula...
T[n] = 1 + T[n-1] * 2
numList = []
numLisst.append (1)
#Begins with a term 1.
def numSequence ():
while True:
for i in range (1,12):
#Temporally set numbers from 1 to 12
numList[i] == 1+(numList[i-1]*2)
break
print (numList)
numSequence()
First of all, this brings an error, list index out of index
I'd like to see this code produce the fibonacci sequences, for example,,
1, 3, 7, 15, 31, 63, 127 , ....
I hope if I use this recursive program, I would be able to find out specific order of the numbers in an array,
e.g. If I'd like to find out 3rd number in the array, should be whether 7 or 15 (It would depend how I would set it)
The recursive implementation of your formula would be the following, assuming your base case was T(1) = 1
def T(n):
if n == 1:
return 1
else:
return 1 + T(n-1)*2
Some examples
>>> [T(i) for i in range(1,10)]
[1, 3, 7, 15, 31, 63, 127, 255, 511]
>>> T(15)
32767
One way to solve this probem (not most Pythonic implementation, though...)
# T[n] = 1 + T[n-1] * 2
def nextFibonachi(n,i):
n = 1 + n*2
print(str(i)+": "+str(n))
return n,i
fibArr = []
for i in range(0,100):
if i == 0:
n = 0
n,i = nextFibonachi(n, i)
fibArr.append(n)
print(fibArr)
m = 10
print("\n"+str(m)+": "+str(fibArr[m]))
I have a while loop that is looping over a list trying to find the number 1. I have the code below and it loops over "almost" all the list but it does not find the index for value 1
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
counter = 0
number_to_find = 1
def my_loop():
global counter
while counter > 6: #Also not sure while 7 doesn't work, says out of range?
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
print my_loop()
This is a very confusing bit of code.
You print the output, but the function does not return anything. (It also prints things, but it does not return anything.)
The function has a while loop and also recurs upon itself. (There are some cases where this is appropriate, but this is not one of them.)
counter is initially 0, but your first check is if counter > 6. 0 is not greater than six. (This is not technically wrong, but very confusing.)
The value 1 is at index 5. Why are you looking for 6?
Once you have reached the desired index, you do not terminate the loop.
You can achieve what you're looking for using the following piece of code:
numbers = [24, 10, 92, 28, 71, 1, 80, 1, 70]
number_to_find = 1
for i,j in enumerate(numbers):
if j == number_to_find:
print i, "=>", j
# Output
>>> 5 => 1
>>> 7 => 1
If your numbers doesn't contains repeated numbers, you can use the following piece of code, as sugested by kojiro:
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
number_to_find = 1
print numbers.index(number_to_find)
# Output
>>> 5
But if your code contains repeated chars, it'll show only the first ocurrence:
numbers = [24, 10, 92, 28, 71, 1, 80, 1, 70]
number_to_find = 1
print numbers.index(number_to_find)
# Output
>>> 5
while counter > 6:
If counter is greater than 6, it must be 7 or greater. If you're looping while counter > 7, you're indexing out of the range of the size of the list (which is indexed from 0 to 7).
global counter
Don't do this. You shouldn't use globals. There are good reasons
def my_loop():
...
my_loop()
You don't need recursion for this. This is quite simple with just a for loop (in fact, you can do it without that).
I'll post a few ways to solve this problem:
enumerate
def find_needle(needle, haystack):
for idx, item in enumerate(haystack):
if needle == item:
return idx
return None
index
def find_needle(needle, haystack):
return haystack.index(needle)
These two implementations don't do exactly the same thing - the first will return None if needle isn't found in haystack, where the second will throw a ValueError. I think the former is more forgiving, but it's up to you.
So there are many ways to do this, iteratively and recursively but to take the OP's code as is and what I think they were attempting.
Note: it is generally considered bad practice to use global variables, you should pass the list of numbers and the number to find to the function.
Note: your while loop is effectively implementing a for loop - for counter in range(len(numbers)): would provide the same result
numbers = [24, 10, 92, 28, 71, 1, 80, 70]
number_to_find = 1
def my_loop():
counter = 0
while counter < len(numbers):
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
Output:
Counter not found in position 0
Counter not found in position 1
Counter not found in position 2
Counter not found in position 3
Counter not found in position 4
Number found at position 5
Counter not found in position 6
Counter not found in position 7
Doing the same thing with a for loop:
for counter in range(len(numbers)):
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
Would output the same.
However, perhaps a more idiomatic approach for Python would be to use enumerate:
for counter, number in enumerate(numbers):
if number == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
To find first occurence use numbers.index(x) where x is the number you are searching or for all of them indices = [idx for idx, number in enumerate(numbers) if elem_list == x]
For starters, I think you mean for your else block to correspond to the if. Right now it's associated with the while. Indent the else so it's aligned with the if, and then indent the three lines after the else to align with the print after the if:
if numbers[counter] == number_to_find:
print "Number found at position", counter
else:
print "Counter not found in position" , counter
counter = counter + 1
my_loop()
Once you fix that, your second problem will be that your program will exit immediately because your while condition evaluates to 0 > 6, which is false, so the if block will never even run. Minimally you'll want to change the > to <. At that point, your code will mostly work like you expect it to, but consider:
The application will go into an infinite loop once it finds the value it's looking for.
A for loop would be much nicer than a while with a counter.
You should really avoid using global variables if at all possible (it's very possible here).
Okay so I am trying to create an empty list, then add integers to the list to then pick out the highest,lowest and 5 middle numbers( in descending order using a slice) and put them on display... seems simple enough....
def main():
nums = []
for i in range(20,80,9):
nums.append(i)
print(*nums,sep=' ')
print('The highest number is',max(nums))
print('The lowest number is',min(nums))
print('The middle 5 sorted high to low:')
nums.sort()
nums.reverse()
print (*nums[1:6])
main()
Okay so i edited it using your suggestions and the program works fine..... I just cant wrap my head around that damned while loop.... Can anyone see how I could integrate that?
while nums.append(i):. list.append returns None, and None does not evaluate to true. So your print statements will never be executed.
nums.reverse[2:6] reverse is a method and reverses the list in place. It does not return anything. So this part will throw a TypeError. You want to instead call nums.reverse()
The reverse method does not sort. You need nums.sort()
nums[2:6] will get you the elements from index 2 to 6 (exclusive). So this will only get you 4 elements. Additionally, your list has 9 elements (7 if you exclude the min and max). The middle 5 elements would not be between index 2 and 6.
Python has a help() function, use it if you need to know what functions/methods return.
You could refactor your code to use a while loop like so.
def main():
nums = []
i = 20
while i < 80:
nums.append(i)
print(*nums,sep=' ')
i += 9
print('The highest number is',max(nums))
print('The lowest number is',min(nums))
print('The middle 5 sorted high to low:')
# removed on the basis that they are already sorted
#nums.sort()
nums.reverse()
print (*nums[1:6])
main()
It's just a lot nicer using range as you don't need to the i variable outside the scope of the loop.
This is one way to do it:
nums = []
for i in range(20,80,7):
nums.append(i)
mx = max(nums)
mn = min(nums)
nums.remove(mx)
nums.remove(mn)
mx2 = max(nums)
mn2 = min(nums)
nums.remove(mx2)
nums.remove(mn2)
nums.sort()
nums.reverse()
print nums
The output is the 5 middle numbers in descending order:
[62, 55, 48, 41, 34]
and the better, shorter way to do it is this:
def main():
nums = []
for i in range(20,80,7):
nums.append(i)
mx = max(nums)
mn = min(nums)
print "The highest number is %s " % mx
print "The lowest number is %s " % mn
while len(nums) != 5:
nums.remove(max(nums))
nums.remove(min(nums))
nums.sort()
nums.reverse()
print "The middle 5 sorted high to low is %s:" % nums
main()
The output is:
The highest number is 76
The lowest number is 20
The middle 5 sorted high to low is [62, 55, 48, 41, 34]