Python binary search recursive if possible - python

class SortedList:
theList = []
def add(self, number):
self.theList.append(number)
return self.theList
def remove(self, number):
self.theList.remove(number)
return self.theList
def printList(self):
return print(self.theList)
def binarSearch(self, number):
middle = (len(self.theList)//2)
end = len(self.theList)
if end != 0:
if int(self.theList[middle]) == int(number):
return print("The number is found in the list at place",middle+1)
elif int(self.theList[middle]) < int(number):
self.theList = self.theList[middle:]
return self.binarSearch(number)
elif int(self.theList[middle]) > int(number):
self.theList = self.theList[:middle]
return self.binarSearch(number)
else:
return print("The list is empty")
sorted = SortedList() #create a SortedList object
sorted.add("1")
sorted.add("2")
sorted.add("3")
sorted.add("4")
sorted.add("5")
sorted.add("6")
sorted.printList()
sorted.binarSearch(3)
I cannot use additional parameters I mut use only self and number. I want to make it recursive but if it is hard you can answer as normal.
This code works good until the number 4. When I give 4 for searching it says it is in place 2 and it continues saying two after 4. I have tried adding other numbers but it is same

Python already has a great module bisect which performs a binary search for sorted lists:
import bisect
l = [2,3,1,5,6,7,9,8,4]
print(bisect.bisect(l, 4)) # Output: 3
Familiarize yourself with this library:
https://docs.python.org/3.5/library/bisect.html

Just a hint: You can use additional parameters if you give them default values. Your method signature would look like this:
def binarSearch(self, number, start=0, end=len(self.theList)):
So it could still be called like sorted.binarySearch(5) but would internally be able to pass the state correctly.

Related

Python classes and definitions

Here is my python code:
class Solution():
def isPalindrome(self):
return str(self.x) == str(self.x)[::-1]
s1 = Solution()
s1.x = 121
s1.isPalindrome()
It checks to see if the input is a palindrome. I want to create a new object that has the x value 121 and when I execute the isPalindrom function, I want it to return either a true or false boolean answer.
Currently when I run this program, nothing gets outputted. I am a bit lost as to where to go from here, would appreciate help.
Just print out the return value of isPalindrome(), because if you have a line with only a return value (this case being a boolean), the compiler won't know what to do with it.
class Solution():
def isPalindrome(self):
return str(self.x) == str(self.x)[::-1]
s1 = Solution()
s1.x = 121
print(s1.isPalindrome())
You're not telling the program to print anything. Try using print to make it reveal the answer.
Along with printing results we can also make class more pythonic.
class Solution:
def __init__(self):
self.input = None
def is_palindrome(self):
if isinstance(self.input, str):
return self.input == self.input[::-1]
print("Error: Expects str input")
return False # or leave blank to return None
s1 = Solution()
print(s1.is_palindrome())
s1.input = "121"
print(s1.is_palindrome())
output
Error: Expects str input
False
True
The main idea here is divide number. let's take number 122. First of all you need store it in a variable, in this case r_num. While loop is used and the last digit of the number is obtained by using the modulus operator %. The last digit 2 is then stored at the one’s place, second last at the ten’s place and so on. The last digit is then removed by truly dividing the number with 10, here we use //. And lastly the reverse of the number is then compared with the integer value stored in the temporary variable tmp if both are equal, the number is a palindrome, otherwise it is not a palindrome.
def ispalindrom(x):
r_num = 0
tmp = x
while tmp > 0:
r_num = (r_num * 10) + tmp % 10
tmp = tmp // 10
if x == r_num:
return True
return False

Stacks and optimization - example from hackerrank

I have a question concerning stacks in Python. I tried to solve a Maximum Element task in Hackerrank:
You have an empty sequence, and you will be given N queries. Each query
is one of these three types:
1 x -Push the element x into the stack.
2 -Delete the element present at the top of the stack.
3 -Print the maximum element in the stack.
The first line of input contains an integer, N. The next N lines each
contain an above mentioned query. (It is guaranteed that each query is
valid.)
To solve it I wrote something like this:
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def maxEl(self):
return max(self.items)
s = Stack()
for i in range(int(input())):
n = input().split()
if n[0] == '1':
s.push(int(n[1]))
elif n[0] == '2':
s.pop()
else:
print(s.maxEl())
It works, but too slow apparently and I pass only 18 out of 28 testcases (because of timeout). I have found a similar solution, and it is fast enough, but I don't understand why:
class Stack:
def __init__(self):
self.arr = [0]
self.max = [0]
def push(self, data):
self.arr.append(data)
if self.max[-1] <= data:
self.max.append(data)
def pop(self):
if self.arr[-1] == self.max[-1]:
self.max.pop()
self.arr.pop()
N = int(input())
s = Stack()
for _ in range(N):
x = str(input())
if x[0] == '1':
s.push(int(x[2:]))
elif x[0] == '2':
s.pop()
else:
print(s.max[-1])
Can somebody explain me why my code isn't performing well? Thank you.
The two solutions are pretty similar, except for the code that returns the maximum element in the stack.
In your solution you use the max() function:
def maxEl(self):
return max(self.items)
This runs in O(n) time, since max() must check every element in the worst case.
In the other solution maximum values are stored in yet another stack, so getting the current maximum value is just an index operation, which runs in O(1) time:
s.max[-1]
There's also some cost associated with updating the stack of maximums on each push/pop, but those operations are still constant time.
Given the definition of the problem even the working solution is doing way too much. More specifically you need to remember ONLY the max in the stack; something like
s = []
for _ in range(N):
x = str(input())
if x[0] == '1':
v = int(x[2:])
s.append(v if len(s) == 0 else max(v, s[-1]))
elif x[0] == '2':
s.pop()
else:
print(s[-1])
should be sufficient.

File's Data keeps getting overwritten by function

for some reason I am running into an issue where my function call seems to be overwriting the data read in from the file without me asking it to. I am trying to get the sum of the original list but I keep getting the sum of the squared list.
CODE:
def toNumbers(strList):
for i in range(len(strList)):
strList[i] = strList [int(i)]
return strList
def squareEach(nums):
for i in range(len(nums)):
nums[i] = eval(nums[i])
nums[i] = nums[i]**2
return nums
def sumList(nums):
b = sum(nums)
return b
def main():
file=open("numbers.txt","r").readline().split(" ")
print(str(squareEach(file)))
print(str(sumList(file)))
Your squareEach function modifies the original list which is passed to it.
To see what's going, consider adding a print between your function calls.
def main():
file=open("numbers.txt","r").readline().split(" ")
print(str(squareEach(file)))
print(str(file))
print(str(sumList(file))
EDIT:
The simplest fix would be to use a different list for storing your square numbers inside squareEach function
def squareEach(nums):
squares = []
for i in range(len(nums)):
num = eval(nums[i])
squares[i] = num**2
return squares
There are more efficient ways as suggested in other answers, but in your case, this appears to be the simplest fix.
The list nums is modified in squareEach method. Consider storing the results in a different list variable of the below sort:
def squareEach(nums):
sq = list()
for i in range(len(nums)):
sq.append(str(int(nums[i])**2))
# nums[i] = str(int(nums[i])**2)
return sq
I am not sure whether i am helping . But whatever you are trying to do can be done as follows
file=open("numbers.txt","r").readline().split(" ")
print ([int (m)**2 for m in file])
print (sum([int(m) for m in file]))
And if you want functions
def squareEach(file):
print ([int (m)**2 for m in file])
def sumList(file):
print (sum([int(m) for m in file]))
file=open("numbers.txt","r").readline().split(" ")
squareEach(file)
sumList(file)

Creating chains that loop on themselves

I want to have a number that breaks into 2 other numbers and checks for end conditions, breaking off each number until the conditions are met.
I came up with the following example to try to figure it out. Take a number, and break it into 2 more numbers: one is the original number multiplied by 2 and the other number is the original number divided by 3 without a remainder (//). This continues until a number is either greater than 100, equal to 6, or a square.
I want to record every chain that is made to be returned and printed out at the end. I can only do this by checking the second number in a chain currently and am not clever enough to figure out how to check both numbers. I want a new chain to be created every time the number is broken into 2 new numbers.
Currently, here is what I have:
import numpy as np
def check_conditions(number):
if number > 100:
return False
if number == 6:
return False
if np.sqrt(number) % 1 == 0:
return False
return True
def find_decay(number):
'''
Rule: Number is broken into two chains. First chain is
mulitplied by 2. Seconds chain is // 3. Same thing happens
to both chains unless end condition is met:
1. number is greater than 100
2. number is equal to 6
3. number is a perfect square
'''
master_chain = []
while check_conditions(number):
new_chain1 = [number * 2]
master_chain.append(new_chain1)
new_chain2 = [number // 3]
master_chain.append(new_chain2)
number = new_chain2[-1]
return master_chain
if __name__ == '__main__':
print find_decay(int(raw_input('Number: ')))
Does anyone have any ideas of ways to check conditions in a while loop for 2 separate numbers like?
This sort of problem typically lends itself to trees and/or recursion. However, the rate at which you're spawning new work is quite high compared to the rate at which you're going to satisfy the conditions. (ie while it won't take too many operations to exceed 100 for one product of each value, but low chances of finding a perfect square or exactly 6 on either fork)
Therefore, you'll want to set a max recursion depth for your implementation else you'll come up against the interpreter's limit (sys.getrecursionlimit()) and fail ugly.
I've provided a simple example of how you might do it below, recursively building a tree.
This is not particularly efficient though, and if you are interested in very long 'chains' then you may need to consider addressing this another way.
import sys
import numpy as np
class Node(object):
def __init__(self,number,parent):
self._parent = parent
self._number = number
self._satisfied = number > 100 or number == 6 or np.sqrt(number) % 1 == 0
self._left = None
self._right = None
self._depth = parent.depth + 1 if parent != None else 1
#property
def parent(self):
return self._parent
#property
def number(self):
return self._number
#property
def satisfied(self):
return self._satisfied
#property
def depth(self):
return self._depth
#property
def left(self):
return self._left
#left.setter
def left(self,value):
self._left = value
#property
def right(self):
return self._right
#right.setter
def right(self,value):
self._right = value
def print_all_chains(node,chain=[]):
if node.left is None:
chain.append(node.number)
print '{0}: {1}'.format(node.satisfied, chain)
else:
print_all_chains(node.left, chain[:] + [node.number])
print_all_chains(node.right, chain[:] + [node.number])
def build_tree(node, maxDepth):
if not node.satisfied and node.depth<maxDepth:
node.left = Node(node.number*2, node)
build_tree(node.left,maxDepth)
node.right = Node(node.number//3, node)
build_tree(node.right,maxDepth)
def find_decay(number):
root = Node(number,None)
build_tree(root,maxDepth=10)
print_all_chains(root)
if __name__ == '__main__':
find_decay(int(raw_input('Number: ')))
Using a simple Node class, this can give you an idea of the tree structure. This traverses the tree in level-order (which guarantees to find the shortest chain):
from collections import deque
import numpy as np
def check_conditions(number):
return number > 100 or number == 6 or np.sqrt(number) % 1 == 0
class Node():
def __init__(self, value, parent=None):
self.value, self.parent = value, parent
def chain(self):
node = self
while node:
yield node.value
node = node.parent
def find_decay(number):
agenda = deque([Node(number)])
while agenda:
node = agenda.popleft() # use pop() for depth-first
num = node.value
if check_conditions(num):
return list(node.chain())
agenda.append(Node(num//3, parent=node))
agenda.append(Node(num*2, parent=node))
if __name__ == '__main__':
for x in find_decay(int(raw_input('Number: '))):
print x,
37: 37 12 4

Multiple "is" in Python

I have a list with a few hundred of objects, and I want to check, if a newcomer object is already added to my list (not an equal object, but exactly this exact instance).
I have a dumb realization like this:
def is_one_of(test_object, all_objects):
for elm in all_objects:
if test_object is elm:
return True
return False
Cannot it be more beautiful?
use any:
if any(x is test_object for x in all_objects):
The example in the python reference looks remarkably similar to your code already :)
Use the any() function:
def is_one_of(test_object, all_objects):
return any(test_object is elm for elm in all_objects)
It'll stop iterating over the generator expression as soon as a True result is found.
Eh, I made it by putting id(element) to a set:
def _unit_list(self):
"""
Returns all units in the order they should be initialized.
(Performs search by width from start_point).
"""
unit_id_set = set()
unit_list = []
unit_id_set.add(self.start_point)
unit_list.append(self.start_point)
pos = 0
while pos < len(unit_list):
cur_unit = unit_list[pos]
for child in cur_unit.links_to:
if not (id(child) in unit_id_set):
unit_list.append(child)
unit_id_set.add(id(child))
pos += 1
return unit_list
You can use
if any(test_object is x for x in all_objects): ...
if you need to do this test often however may be you can keep a set of all object ids instead
all_ids = set(map(id, all_objects))
then you can check faster with
if id(test_object) in all_ids: ...
Another common solution that may apply is to store in the object itself in a specific field if it has been already processed:
# add the object to the list
all_objects.append(x)
x.added = True
...
# Check if already added
if test_object.added: ...
I think you're looking for the in operator. The equivalent function would be:
def is_one_of(test_object, all_objects):
return test_object in all_objects
(but you really wouldn't want to write that as a function).
Edit: I'm wrong. According to the Expressions page:
For the list and tuple types, x in y is true if and only if there exists an index i such that x == y[i] is true.
That would work if your class doesn't define __eq__, but that's more fragile than I'd want to rely on. For example:
class ObjWithEq(object):
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
a = ObjWithEq(1)
b = ObjWithEq(1)
assert a == b
assert a in [b]
class ObjWithoutEq(object):
def __init__(self, val):
self.val = val
a = ObjWithoutEq(1)
b = ObjWithoutEq(1)
assert a != b
assert a not in [b]

Categories