Python Recursion List Sum of Pairs - python

I am supposed to write two functions that do the exact same thing but their implementation is different.
The function takes as input a list of positive integers and a positive integer n, and returns True if two of the numbers in list equal to n. Otherwise, it returns False.
The first function is supposed to use a nested a loop, which I was able to get.
The second functions is not supposed to use a nested loop. However, you are supposed to sort the list out and then solve the problem.
Here is what I have for the second function.
def pairs2(lst, n):
lst.sort()
if len(lst) == 2:
if lst[0] + lst[1] == n:
return True
else:
return False
elif len(lst) >= 3:
for i in range(len(lst) - 1):
if lst[0] + lst[i + 1] == n:
return True
lst.remove(lst[0])
pairs2(lst, n)
The function works until the last two lines are implemented. After that, it doesn't return anything. What is wrong with my function?
Also, are they any other alternatives to that I do not use recursion? I just came up with using recursion since it was the first idea that I got.

A recursive algorithm that eliminates the largest number at each recursive step:
def pairs2(lst, n, s=False):
if len(lst) < 2: return False
if not s: lst = sorted(lst)
for item in lst:
if item + lst[-1] > n:
return pairs2(lst[:-1], n, True)
if item + lst[-1] == n:
print item, lst[-1]
return True
return False
The s parameter indicates whether the list is already sorted or not.

def pairs2(lst, n):
[pair for pair in itertools.combinations(lst,2) if sum(pair) == n]
Instead of using recursion, you could use the brute-force approach to find the pairs using the itertools.combinations.
Read more about itertools: https://docs.python.org/2/library/itertools.html

Related

Binary Search in Python - Iterative Method

so I'm trying to learn programming myself in Python language and was confused implementing Binary Search in Python. So here's what I have done
list = [3,6,8,12,14,17,25,29,31,36,42,47,63,55,62]
key = 42
print(list)
def high(sorted_list):
max_index = len(sorted_list)
return max_index
def low(sorted_list):
start_index = 0
return start_index
def mid(sorted_list):
mid_index = ( low(sorted_list) + (high(sorted_list) - low(sorted_list)) ) // 2
return mid_index
for x in range(4):
if list[mid(list)] < key:
list = list[mid(list)+1:]
elif list[mid(list)] < key:
list = list[mid(list)-1:]
print(list)
I know I should not keep a range number in for loop but I know it will only make 4 comparisons in this example so I hardcoded it. But when I run it, it splits the list only once and keep on printing the second half of the list. Output image:
Ok, I tried your code and had to do a few corrections:
The while loop had to be modified (you knew that)
There wasn't a check for the case where the key is found (see comments)
There was a typo, < instead of > (see comments)
In the same line, the list partition was wrong
The low function was useless (returning a constant value) (see comments)
The high function was useless too (simply returning the value from another function)
The mid function was more complicated than needed (it boiled down to taking a value, then adding and subtracting zero), so it can simply take the value
Ah, btw the input list is not sorted in your example.
This is my proposal:
def mid(lst):
return len(lst) // 2
def bin_search(lst, k):
while lst:
i = mid(lst)
if lst[i] == k:
return True
if lst[i] < k:
lst = lst[i+1:]
elif lst[i] > k:
lst = lst[:i]
else:
return False
bin_search([3,6,8,12,14,17,25,29,31,36,42,47,55,62,63], 42)
True
bin_search([3,6,8,12,14,17,25,29,31,36,42,47,55,62,63], 58)
False

Adding two sum with recursion

Question: Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.Each input would have exactly one solution, and you may not use the same element twice. for example.
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Output: Because nums[0] + nums[1] == 9, we return [0, 1].
I'm trying one make a helper function that add the first number with each of the rest number, and run this helper function recursively on the give list nums. I'm not sure where my codes is wrong. (I know there are other more efficient algorithms, for the purpose of exercise pls stick to this approach)
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# One function that takes a list, and find out first + i ==target, if exists
def help_(lst,tar):
for i, n in enumerate(lst[1:],start=1):
if lst[0]+n ==tar:
return i
else:
return False
ctn=0
#base case, if a sublist whose first num + another another is target
if help_(nums,target) != False:
return [0+ctn,help_(nums,target)+ctn] # return two indices from helper, adding the time it looped
else:
ctn =+1
return help_(nums[1:],target)
There are a few issues:
Your recursive call return help_(nums[1:],target) will not return a pair, but one index (or False), so this should never be returned in the main function. Instead make the recursive call on twoSum, which will return a pair (if successful). Then you will still need to add 1 to both indices before returning that.
The helper function is returning always in the first iteration of the loop. You should move the return False out of the loop's body.
It is a pity that you call the helper function twice with the same arguments. Just store the result in a temporary variable to avoid re-executing it
Here is your code with those corrections:
class Solution:
def twoSum(self, nums, target):
# One function that takes a list, and find out first + i ==target, if exists
def help_(lst,tar):
for i, n in enumerate(lst[1:],start=1):
if lst[0]+n ==tar:
return i
return False
ctn=0
res = help_(nums,target)
if res != False:
return [0+ctn, res+ctn]
else:
ctn =+1
x, y = self.twoSum(nums[1:], target)
return x+1, y+1
As you noted in your question this is not the most efficient way to solve this problem.
Using a dictionary leads to a better time complexity. In case you cannot find it, here is such a solution (spoiler):
d = { target - num: i for i, num in enumerate(nums)}`
return next((i, d[j]) for i, j in enumerate(nums) if j in d.keys() and i != d[j])
Your approach is globally valid (the implementation is not) but you have to keep track of a lot of parameters
The ideal is to only check the combinations:
nums = [2,7,11,15]
s = 9
from itertools import combinations
for (i,a),(j,b) in combinations(enumerate(nums), r=2):
if a+b == s:
print(i,j)
Output: 0 1
NB. I purposely proposed an answer with a module to give you the chance to rewrite it with a classical loop
for i in range(len(nums) - 1):
for j in range(i + 1, len(nums)):
total = nums[i] + nums[j]:
if total == target:
return nums[i], nums[j]

Summing the elements of a list recursively

def sum(L):
if len(L) == 1:
return L[0]
i = sum (len (L) // 2)
if len(L) > 1:
return i + i
L=[2,4]
print (sum(L))
when i try to run it there is a TypeError: object of type 'int' has no len().
In sum (len (L) // 2), you're passing an integer (the result of len(L) // 2) as the L argument to your sum() function. (Please don't give functions the same name as built-in functions.) The recursively-called sum() then tries to evaluate len(L) == 1 on this integer, but integers don't support len(), and so you get the error message in question. What exactly are you actually trying to do?
I think what you were aiming for was to write a recursive sum function that continuously splits the list into smaller chunks. So basically what you need to do is compute the index of the midpoint, then use list slicing to pass the first sublist and second sublist recursively back into the function, until hitting your base case(s) of 0 or 1 elements remaining.
def add(values):
if len(values) == 0:
return 0
elif len(values) == 1:
return values[0]
mid = len(values)//2
return add(values[:mid]) + add(values[mid:])
>>> add([1,2,3,4,5])
15
Don't name your function sum, it shadows the builtin function
Implement your function so as to clearly define a base case and a recursive case.
For the base case, when the length is 1, return that element. You've got this right.
For the recursive case, split your list into half and recursively compute the sum for each half.
def sum_recursive(L):
if len(L) == 1:
return L[0]
idx = len(L) // 2
return sum_recursive(L[:idx]) + sum_recursive(L[idx:])
sum_recursive must always receive a list and return an integer.
Some dry runs:
In [5]: sum_recursive([1, 2, 4, 8])
Out[5]: 15
In [6]: sum_recursive([2, 4])
Out[6]: 6
Keep in mind that this won't be able to handle empty lists as input. If you want to account for that as well, change your base case to:
def sum_recursive(L):
if len(L) <= 1:
return sum(L)
...
We're making use of the builtin sum function here which handles empty lists gracefully by returning 0. For single-element lists, the first element is returned (this is also why it is important you don't shadow these utility functions).
If you don't want to use sum there, you'll need to split your base case into two parts:
def sum_recursive(L):
if len(L) == 0:
return 0
elif len(L) == 1:
return L[0]
...
In your code
i = sum (len (L) // 2)
line is throwing an error because in recursion after the first call of sum() you are passing an integer not list
def sum(L):
if len(L) == 0:
return 0
elif len(L) == 1:
return L[0]
else:
index = len(L)-1
return L[index] + sum(L[0:index])
L=[2,4]
print (sum(L))

How can I return a single boolean value from a recursive function?

I have this function:
def most(P, S):
def recursion(P,S):
if len(S) == 0:
return []
elif P(S[0]):
return [P(S[0])] + recursion(P, S[1:])
else:
return recursion(P, S[1:])
if len(recursion(P,S)) > len(S)/2:
return True
else:
return False
It takes an input of function, P and list, S. If the result of P(S[i]) is true for most of S, then the function most() should return true. Any idea how I can do this recursively without a function inside of a function? In other words, how can I return a single boolean value from a recursive function that takes a list as its input?
Thanks!
The biggest key to recursion is understanding the "terminal condition." What is the state where the function must stop? In this case, it's the empty list.
def most(pred, lst):
if lst == []:
return # but what do we return?
You will need to keep track of the number of list elements that meet an expectation... so you have to keep track of both the expectation (i.e. how many have to be true in order for "most" to be true), as well as the count so far. Let's add those...
def most(pred, lst, threshold=None, count=0):
if threshold is None:
threshold = len(lst) // 2
if lst == []:
return count > threshold
So, then we need to "deconstruct" the list so that we can recurse over it. Let's add that...
def most(pred, lst, threshold=None, count=0):
if threshold is None:
threshold = len(lst) // 2
if lst == []:
return count > threshold
# Check the 'truth' of the head of the list...
if pred(lst[0]):
count += 1
# ...and pass the tail of the list into the next iteration.
return most(pred, lst[1:], threshold, count)
That should be all that you need. Now, I'll caution you that if your lists are of significant length, Python will blow its stack. This is also significantly slower than a solution using a for loop or reduce, because of all the additional function calls.
If I were implementing most for production code, I would do this:
def most(pred, lst):
return sum(1 for x in lst if pred(x)) > len(lst) // 2

Recursion depth error in simple Python program

I am new to programming, and was trying to solve this problem on Project Euler using basic Python.
Essentially, I tried to use recursion based on the largest value chosen at every stage, and using a list to maintain possible options for future choices.
The code is short and is given below:
def func(n,l):
if n<0:
return 0
if l==[1] or n==0:
return 1
else:
j=0
while l != []:
j=j+func(n-l[0],l)
del l[0]
return j
print func(200,[200,100,50,20,10,5,2,1])
For instance, if we have
func(5,[5,2,1])
the recursion splits it into
func(0,[5,2,1]) + func(3,[2,1]) + func(4,[1])
But the code never seems to go through. Either it says that there is a list-index-out-of-range error, or a maximum-recursion-depth error (even for very small toy instances). I am unable to find the mistake. Any help will be much appreciated.
In Python lists are passed into functions by reference, but not by value. The simplest fix for your program is changing recursive call to func(n - l[0], l[:]). In this way list will be passed by value.
One thing you're failing to take into account is that the following:
j=j+func(n-l[0],l)
doesn't make a copy of l.
Therefore all recursive invocations of func operate on the same list. When the innermost invocation deletes the last element of l and returns, its caller will attempt to del l[0] and will get an IndexError.
At each recursion, make the following 2 decisions:
Take the first coin (say f) from available coin types, then check if we can made (n-f) from those coins. This results in a sub-problem func(n - f, l)
Ignore the first coin type, and check if we can make n from the remaining coin types. This results in a sub-problem func(n, l[1:])
The total number of combinations should be the sum of the two sub-problems. So the code goes:
def func(n, l):
if n == 0:
return 1
if n < 0 or len(l) == 0:
return 0
if l == [1] or n == 0:
return 1
return func(n - l[0], l) + func(n, l[1:])
Each recursion a copy of l is made by l[1:]. This can be omitted by pop element before next recursion and restore with append afterwards.
def func(n, l):
if n == 0:
return 1
if n < 0 or len(l) == 0:
return 0
if l == [1] or n == 0:
return 1
full = func(n - l[-1], l)
last = l.pop()
partial = func(n, l)
l.append(last)
return full + partial

Categories

Resources