Recursive function in Python throwing an error - python

Trying to do this question I got on leetcode.com in python:
Given a sorted (in ascending order) integer array nums of n elements and a target value, write a function to search target in nums. If target exists, then return its index, otherwise return -1.
Example 1:
Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 exists in nums and its index is 4
Example 2:
Input: nums = [-1,0,3,5,9,12], target = 2
Output: -1
Explanation: 2 does not exist in nums so return -1
Note:
You may assume that all elements in nums are unique.
n will be in the range [1, 10000].
The value of each element in nums will be in the range [-9999, 9999].
FIRST ATTEMPT
class Solution(object):
count = 0;
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
if (nums[count] == target):
return count;
elif(count +1 >len(nums)):
return -1;
else:
count += 1;
return search(self, nums, target);
My Second attempt was the same exact code except the following line:
count = 0;
was put right after the function definition:
def search(self, nums, target):
Input:
nums = [-1,0,3,5,9,12]
target = 9
Expected Answer: 4
(First Attempt) Actual Answer:
Line 10: UnboundLocalError: local variable 'count' referenced before assignment
(Second Attempt) Actual Answer:
Line 16: NameError: global name 'search' is not defined
I looked up recursive functions with python on the web and it didn't offer too much help as all the example code is more or less the same. Any help will be appreciated!

Your problems have nothing to do with recursion, but rather with misuse of class members.
UnboundLocalError: local variable 'count' referenced before assignment means that you use return count and count += 1, but never initialized it to anything. Presumably, you either want to do count = 0 in the method body, or use self.count instead.
NameError: global name 'search' is not defined is because you're calling a class method wrong. self is special on class methods, so instead of search(self, nums, target), do self.search(nums, target).

You need to use self.search and also I think there is a better way to solve the problem
The question is basically related to Binary Search. You can learn more about it at this https://www.geeksforgeeks.org/binary-search/
I am also attaching the code in Python for reference along with test data. Hope it helps
def binarySearch (nums, left, right, target):
if right >= left:
mid = left + (right - left)/2
if nums[mid] == target:
return mid
elif nums[mid] > target:
return binarySearch(nums, left, mid-1, target)
else:
return binarySearch(nums, mid + 1, right, target)
else:
return -1
nums = [-1,0,3,5,9,12]
target = 9
result = binarySearch(nums, 0, len(nums)-1, target)
print result

Related

name ___ is not defined - recursive fibonacci memoization

NameError: name 'fib_cache' is not defined
So I am trying to implement the fibonacci number sequence using memoization, but I keep getting this error in leetcode and I am not sure why. Can anyone point me in the right direction?
class Solution:
fib_cache = {}
def fib(self, n: int) -> int:
value;
if n <=1:
value = n;
elif n>2:
value = fib(n-1) + fib(n-2);
fib_cache[n] = value
return value
I fixed some lines in your code and now it works. And actually you were not using memoization in your code so I fixed this ,too.
class Solution:
fib_cache = {}
def fib(self, n: int) -> int:
value = 0 # You don't need this line
if n in Solution.fib_cache: # this adds the memoziation idea
return Solution.fib_cache[n]
if n <=1:
value = n
elif n>=2: # <==== Fixed this line
value = self.fib(n-1) + self.fib(n-2) # <==== Fixed this line
Solution.fib_cache[n] = value # <==== Fixed this line
return value
s = Solution() # You don't need these 2 lines in leetcode
print(s.fib(5)) # I wrote them for testing
Output: 5

Print v. Return Statement

In doing this (https://leetcode.com/problems/rotate-array/) leetcode question I am printing the correct result, but returning an incorrect result.
I must be missing something because I should be printing and returning the same thing.
My stdout (print statement) matches the 'expected' result; however, my output doesn't...
Compiled Result
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
new_nums = [ ]
new_index = 0
old_index = len(nums)-k
# Fill in the 'beginning' portion of new array
while(new_index<k):
new_nums.append(nums[old_index])
new_index += 1
old_index += 1
old_index = 0 # reset 'old_index' accordingly
# Fill in the 'end' portion of new array
while(new_index<len(nums)):
new_nums.append(nums[old_index])
new_index += 1
old_index += 1
print(new_nums)
return new_nums
Notice this comment at the top of the code: Do not return anything, modify nums in-place instead. This clearly indicates your function should not return the values, but should modify the nums list that is passed in as the first (non-self) argument.
You will need to use list operations, such as list.append(), list.remove(), list.pop() to achieve the desired goal.
Happy coding!

Given a list of integers, return true if the length of the list is greater than 1

I'm try learning to Python and I need given a list of integers, return true if the length of the list is greater than 1 and the first element and the last element are equal. Here is my code:
class Solution:
def solve(self, nums):
nums = []
if len(nums) > 1 and nums[0]== nums[-1]:
return True
return False
But I get this error:
if len(nums) > 1 and nums[0]== nums[-1]:IndentationError: unexpected indent
You could write it like
class Solution:
def solve(self, nums):
return (len(nums) > 1 and nums[0] == nums[-1])
You were initializing the nums again and again to have zero elements plus the indention was wrong.
You got it almost right, if statement should be nested inside the solve method, however since you are returning True or False you can skip that and you don't need the nums list either, so do this:
class Solution:
def solve(self, nums):
return len(nums) > 1 and nums[0]== nums[-1]
The error you got is an indentation error. In python, you should use either space or tab to represent body of a function or class ,like curly braces in c++ or javascript. It is important to note that you should keep equal indentation for each line inside a body segment. i.e, if you start writing a function by giving 2 spaces as indentation,you should use 2 spaces for all the lines in the function body. The best way is to use tab instead of spaces so that you may not be confused with the number of spaces. Please take into account that you cannot use space and tab at a time.
I have edited your code as,
class Solution:
def solve(self, nums):
return (len(nums) > 1 and nums[0]== nums[-1])
you can call the function as,
obj=Solution()
obj.solve([1,2,3,4,1])
try this:
class Solution:
def solve(self, nums):
if len(nums) > 1 and nums[0]== nums[-1]:
return True

how to Find the largest element in a list using recursion python?

i = 0
def find_max(seq):
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
I do not know what is wrong with this function? It is a infinite loop.
Please check out the following solution and follow comments:
def find_biggest(_list, max_element, first_run):
"""
_list is a list of floats or integers or both,
max element is used to store max value,
first run checks if _list is not empty
"""
if first_run and not _list: # check if _list is not empty
raise ValueError("_list should have float or integer values inside")
first_run = False
if not _list: # exit from recursion, we checked all elements
return max_element
element = _list.pop() # take one element
if type(element) not in (int, float,): # check element type
raise TypeError("_list should contain only int or float values")
if element >= max_element: # check if it is more than max
max_element = element
return find_biggest(_list, max_element, first_run) # next step of recursion
if __name__ == "__main__":
# test
print(find_biggest([-1, 4, 2, 3, 1, 0, 10, 3, 1, 7], 0, True))
# print(find_biggest([], 0, True)) # empty case
# print(find_biggest([-1, 4, 2, 3, "1", 0, 10, 3, 1, 7], 0, True)) # string in list
You can check this:
def find_max(seq):
if len(seq) == 1:
return seq[0]
else:
if seq[0] > seq[1]:
seq.pop(1)
else:
seq.pop(0)
return find_max(seq)
Your code has a lot of indentation issues, that may skip execution of some lines.
Your code should look like this:
i = 0
def find_max(seq):
global i
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
You missed the global, and thus there is no definition of i inside the function.
Your code contains an IndentationError and does not reduce its data on recursive calls - hence data never getting shorter - hence never ending recursion:
def find_max(seq):
if i == len(seq) - 1: # fixed indentation here and below
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq) # never reducing your data size, hence endless
return max(first, max_of_rest)
This would be a fixed recursive solution:
def find_max(seq):
if not seq:
return None # or raise ValueError if you want find_max([]) to crash
if len(seq) == 1:
return seq[0]
else:
return max(seq[0], find_max(seq[1:]))
The problem is inheritently bad for recursive solutions, it is far better to solve it linearly (no max(..) calls needed):
def find_max_lin(seq):
if not seq:
return None
m = seq[0]
for value in seq[1:]:
m = m if value < m else value
return m
or even better simply use the built in max(sequence):
def find_max_builtin(seq):
# no need to create your own function for that though
return max(seq)
See ternary operator for an explanation of what m = m if value < m else value does.
You are using uneeded i variable, in recursion you have base case (your first if), and recursion case, which in this case would be accessing first and second element of your list. As you already checked that the list seq has more than 1 element, you can confidently access positions 0 and 1 of the list.
In your specific case, you are not really using recursion because you never reduce your case, but instead you increment an i variable, whilst recursion is based on always calling the same function with a "simpler" or reduced problem.
With that in mind, several things can be improved in your solution.
i = 0 # Not adviced
def find_max(seq):
# Here you want to check length, making it
# depend on i = problems
if i == len(seq) - 1:
return seq[0]
else:
first = seq[i] # Remove all references to i
i = i + 1 # Remove
# Here you want to call the function with the list
# except the element you know is lower, making the problem
# smaller until you get to the base case
# Instead you are calling find_max with the same
# sequence you had (infinite loop) and returning a
# totally different result.
max_of_rest = find_max(seq)
return max(first, max_of_rest)
A complete solution based on your code would look like this
def find_max(seq):
if len(seq) == 0:
return None
if len(seq) <= 1:
return seq[0]
else:
current_max = max(seq[0], seq[1])
reduced_seq = [current_max] + seq[2:]
return find_max(reduced_seq)
i = 0
def find_max(seq):
global i
if i == len(seq) :
return seq[0]
else:
first = seq[i]
i = i + 1
max_of_rest = find_max(seq)
return max(first, max_of_rest)
print(find_max([-10,2,4,-5]))
thank me later

python list is not copying

In the following subset problem, I'm trying to make a copy of a list object
def findFourPlus(itemCount, seq, goal):
goalDifference = float("inf")
closestPartial = []
subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial=[])
print(closestPartial)
def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
s = sum(partial)
# check if the partial sum is equals to target
if(len(partial) == itemCount):
if s == goal:
print(partial)
else:
if( abs(goal - s) < goalDifference):
goalDifference = abs(goal - s)
print(goalDifference)
print(partial)
print(closestPartial)
closestPartial = copy.deepcopy(partial)
for i in range(len(seq)):
n = seq[i]
remaining = seq[i+1:]
subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])
in the subset function, I am trying to make a copy of the partial list to closestPartial. I've tried
closestPartial = partial
closestPartial = list[:]
closestPartial = list(partial)
closestPartial = copy.copy(partial)
closestPartial = copy.deepcopy(partial)
but in the end all of them seems to be futile. closestPartial remains to be an empty list (which is what I initiated to) for some reason
You are passing closestPartial in as a parameter, so the only thing that will work is an inplace update of its list. All of the examples you give replace the list that was in closestPartial with a new list. But since it wasn't the list you passed in, it doesn't update the real list.
Try:
closestPartial[:] = partial
You can get a feel for the problem by printing the list id before and after the operation.
print id(closestPartial)
...some operation
print id(closestPartial)
if the id changes, that means you created a new list and didn't update the one passed in.
EDIT
Seems I need a better explanation... when you call subset_sum, it creates a local variable called closestPartial that references whatever was passed in as a parameter, in this case a list known to the caller as closestPartial. You now have two variables pointing to the same list. If you reassign the variable, like in closestPartial = partial, those two variables now point to different lists. You didn't update the caller's pointer, you just changed the local variable. Instead, if you don't reassign, changes you make to the one list referenced by both variables are seen by the caller as well - because its the same list.
I suspect that your goalDifference is suffering from the same problem, if you change it in a function and then expect the changed value to somehow get back to the calling function.
Here's some (Python 2 style) code to illustrate what's happening:
#! /usr/bin/env python
def testA(update_func):
seq = []
num = 1
for _ in range(5):
newnum = update_func(seq, num)
print 'testA: ', num, seq, newnum
print
def testB(update_func):
seq = []
num = 1
for _ in range(5):
num = update_func(seq, num)
print 'testB: ', num, seq
print
def update0(seq, num):
#This creates a new list
seq = seq + [num]
num = num + 1
print 'update0:', num, seq
return num
def update1(seq, num):
#This updates the existing list
seq.append(num)
num += 1
print 'update1:', num, seq
return num
def update2(seq, num):
#This updates the existing list
seq[:] = seq + [num]
num += 1
print 'update2:', num, seq
return num
def update3(seq, num):
#This updates the existing list
seq += [num]
num += 1
print 'update2:', num, seq
return num
update_funcs = (update0, update1, update2, update3)
for f in update_funcs:
testA(f)
print '------\n'
for f in update_funcs:
testB(f)
Stack Overflow member Ned Batchelder's article Facts and myths about Python names and values has a good explanation, with cute diagrams.

Categories