Finding the minimum difference between two elements with recursion - python

I'm trying to make a "shortest distance algorithm for 1D".
However, I'm confused on the recursive case. I don't know how to get the value back after the recursive calls (lines 14 and 15). How can I fix the following code?
def recCPairDist(points):
if len(points) == 1:
return 0
elif len(points)== 2:
abs(points[1]-points[0])
#how do i assign the result final value back to "leftDist rightDist"
#since its a recurisive, the result can be more than 1, should i store all the result in a list first?
#then get the min(list)?
else:
mid = len(points) // 2
first_half = points[:mid]
second_half = points[mid:]
leftDist = recCPairDist(first_half)
rightDist = recCPairDist(second_half)
midDist = abs(second_half[0] - first_half[1]) #i dont think this is correct since i didnt consider the recursion
return min(leftDist,rightDist,midDist)
def cPairDist(points):
points.sort()
return recCPairDist(points)
P1 = [7, 4, 12, 14, 2, 10, 16, 6]
cPairDist(P1)
The expected result for P1 should be 1, since the shortest distance would be between 7 and 6.

You're really close! There's three things you have to do:
For the case where there's only one point to consider, you should not return 0. For example, for the array [3, 6, 9], the answer is 3, but your given base case will return 0. This is because one of the resulting subarrays will be of length 1 for odd-length arrays, and the zero return value will propagate when you return from each recursive call.
You need to return the value abs(points[1]-points[0]) in the len == 2 base case explicitly using the return keyword.
For your recursive case, the minimum difference must be between two consecutive elements in the left half, two consecutive elements in the right half, or between the last element of the first half and the first element of the second half (two consecutive elements in the original array, but not covered in the two recursive cases). So, your midDist should compute this value.
Here is a code snippet that resolves all three of these issues:
def recCPairDist(points):
if len(points) == 1:
return float('inf')
elif len(points)== 2:
return abs(points[1]-points[0])
else:
mid = len(points) // 2
first_half = points[:mid]
second_half = points[mid:]
leftDist = recCPairDist(first_half)
rightDist = recCPairDist(second_half)
midDist = abs(first_half[-1] - second_half[0])
return min(leftDist,rightDist,midDist)

Related

How to append to a list two numbers from within the list that add up to a number in the list?

First, I want to find the highest number in the list which is the second number in the list, then split it in two parts. The first part contains the 2nd highest number, while the second part contains the number from the list that sums to the highest number. Then, return the list
eg: input: [4,9,6,3,2], expected output:[4,6,3,6,3,2] 6+3 sums to 9 which is the highest number in the list
Please code it without itertools.
python
def length(s):
val=max(s)
s.remove(val)
for j in s:
if j + j == val:
s.append(j)
s.append(j)
return s
Here's what I have but it doesn't return what the description states.
Any help would be appreciated as I spent DAYS on this.
Thanks,
The main issue in your code seems to be that you are editing the list s whilst iterating through it, which can cause issues with the compiler and is generally just something you want to avoid doing in programming. A solution to this could be iterating through a copy of the original list.
The second problem is that your program doesn't actually find the second biggest value in the list, just a value which doubles to give you the biggest value.
The final problem (which I unfortunately only noticed after uploading what I thought was a solution) is that the split values are appended to the end of the list rather than to the position where originally the largest value was.
Hopefully this helps:
def length(array):
val = max(array)
idx = array.index(val) # gets the position of the highest value in the array (val)
array.remove(val)
for i in array.copy(): # creates a copy of the original list which we can iterate through without causing buggy behaviour
if max(array) + i == val:
array = array[:idx] + [max(array), i] + array[idx:]
# Redefines the list by placing inside of it: all values in the list upto the previous highest values, the 2 values we got from splitting the highest value, and all values which previously went after the highest value.
return array
This will return None if there is no value which can be added to the second highest value to get the highest value in the given array.
Input:
print(length([1,2,3,4,5]))
print(length([4,8,4,3,2]))
print(length([11,17,3,2,20]))
print(length([11,17,3,2,21]))
Output:
[1, 2, 3, 4, 4, 1]
[4, 4, 4, 4, 3, 2]
[11, 17, 3, 2, 17, 3]
None
Here are the docs on list slicing (which are impossible to understand) and a handy tutorial.
when you say "The first part contains the 2nd highest number" does that mean second highest number from the list or the larger of the two numbers that add up the largest number from list?
Here I assume you just wanted the larger of the two numbers that add up to the largest number to come first.
def length(s:list):
#start by finding the largest value and it's position in the list:
largest_pos = 0
for i in range(len(s)):
if s[i] > s[largest_pos]:
largest_pos = i
# find two numbers that add up to the largest number in the s
for trail in range(len(s)):
for lead in range(trail, len(s)):
if (s[trail] + s[lead]) == s[largest_pos]:
if s[trail] > s[lead]:
s[largest_pos] = s[trail]
s.insert(largest_pos +1, s[lead])
else:
s[largest_pos] = s[lead]
s.insert(largest_pos + 1, s[trail])
return s
# if no two numbers add up to the largest number. return s
return s
Since you are limited to 2 numbers, a simple nested loop works.
def length(s):
val = max(s)
idx = s.index(val)
s.remove(val)
for i in range(len(s) - 1):
for j in range(i + 1, len(s)):
if s[i] + s[j] == val:
s = s[:idx] + [s[i], s[j]] + s[idx:]
return s
print(length([4,9,6,3,2]))
Output:
[4, 6, 3, 6, 3, 2]
I used deque library
first to find the highest element or elements then remove all of them and replace them with second high value and rest like : 9 replace with 6 and 3 in example:
from collections import deque
l = [4, 9, 6, 3, 2]
a = deque(l)
e = a.copy()
s = max(a)
while s in a:
a.remove(s) # remove all highest elements
s2 = max(a) # find second high value
c = s - s2
for i in l:
if i == s:
w = e.index(i) # find index of high values
e.remove(max(e))
e.insert(w, s2)
e.insert(w+1, c)
print(list(e))

How can I get a sum from some elements of a list? [duplicate]

I have a list of numbers. I also have a certain sum. The sum is made from a few numbers from my list (I may/may not know how many numbers it's made from). Is there a fast algorithm to get a list of possible numbers? Written in Python would be great, but pseudo-code's good too. (I can't yet read anything other than Python :P )
Example
list = [1,2,3,10]
sum = 12
result = [2,10]
NOTE: I do know of Algorithm to find which numbers from a list of size n sum to another number (but I cannot read C# and I'm unable to check if it works for my needs. I'm on Linux and I tried using Mono but I get errors and I can't figure out how to work C# :(
AND I do know of algorithm to sum up a list of numbers for all combinations (but it seems to be fairly inefficient. I don't need all combinations.)
This problem reduces to the 0-1 Knapsack Problem, where you are trying to find a set with an exact sum. The solution depends on the constraints, in the general case this problem is NP-Complete.
However, if the maximum search sum (let's call it S) is not too high, then you can solve the problem using dynamic programming. I will explain it using a recursive function and memoization, which is easier to understand than a bottom-up approach.
Let's code a function f(v, i, S), such that it returns the number of subsets in v[i:] that sums exactly to S. To solve it recursively, first we have to analyze the base (i.e.: v[i:] is empty):
S == 0: The only subset of [] has sum 0, so it is a valid subset. Because of this, the function should return 1.
S != 0: As the only subset of [] has sum 0, there is not a valid subset. Because of this, the function should return 0.
Then, let's analyze the recursive case (i.e.: v[i:] is not empty). There are two choices: include the number v[i] in the current subset, or not include it. If we include v[i], then we are looking subsets that have sum S - v[i], otherwise, we are still looking for subsets with sum S. The function f might be implemented in the following way:
def f(v, i, S):
if i >= len(v): return 1 if S == 0 else 0
count = f(v, i + 1, S)
count += f(v, i + 1, S - v[i])
return count
v = [1, 2, 3, 10]
sum = 12
print(f(v, 0, sum))
By checking f(v, 0, S) > 0, you can know if there is a solution to your problem. However, this code is too slow, each recursive call spawns two new calls, which leads to an O(2^n) algorithm. Now, we can apply memoization to make it run in time O(n*S), which is faster if S is not too big:
def f(v, i, S, memo):
if i >= len(v): return 1 if S == 0 else 0
if (i, S) not in memo: # <-- Check if value has not been calculated.
count = f(v, i + 1, S, memo)
count += f(v, i + 1, S - v[i], memo)
memo[(i, S)] = count # <-- Memoize calculated result.
return memo[(i, S)] # <-- Return memoized value.
v = [1, 2, 3, 10]
sum = 12
memo = dict()
print(f(v, 0, sum, memo))
Now, it is possible to code a function g that returns one subset that sums S. To do this, it is enough to add elements only if there is at least one solution including them:
def f(v, i, S, memo):
# ... same as before ...
def g(v, S, memo):
subset = []
for i, x in enumerate(v):
# Check if there is still a solution if we include v[i]
if f(v, i + 1, S - x, memo) > 0:
subset.append(x)
S -= x
return subset
v = [1, 2, 3, 10]
sum = 12
memo = dict()
if f(v, 0, sum, memo) == 0: print("There are no valid subsets.")
else: print(g(v, sum, memo))
Disclaimer: This solution says there are two subsets of [10, 10] that sums 10. This is because it assumes that the first ten is different to the second ten. The algorithm can be fixed to assume that both tens are equal (and thus answer one), but that is a bit more complicated.
I know I'm giving an answer 10 years later since you asked this, but i really needed to know how to do this an the way jbernadas did it was too hard for me, so i googled it for an hour and I found a python library itertools that gets the job done!
I hope this help to future newbie programmers.
You just have to import the library and use the .combinations() method, it is that simple, it returns all the subsets in a set with order, I mean:
For the set [1, 2, 3, 4] and a subset with length 3 it will not return [1, 2, 3][1, 3, 2][2, 3, 1] it will return just [1, 2, 3]
As you want ALL the subsets of a set you can iterate it:
import itertools
sequence = [1, 2, 3, 4]
for i in range(len(sequence)):
for j in itertools.combinations(sequence, i):
print(j)
The output will be
()
(1,)
(2,)
(3,)
(4,)
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)
Hope this help!
So, the logic is to reverse sort the numbers,and suppose the list of numbers is l and sum to be formed is s.
for i in b:
if(a(round(n-i,2),b[b.index(i)+1:])):
r.append(i)
return True
return False
then, we go through this loop and a number is selected from l in order and let say it is i .
there are 2 possible cases either i is the part of sum or not.
So, we assume that i is part of solution and then the problem reduces to l being l[l.index(i+1):] and s being s-i so, if our function is a(l,s) then we call a(l[l.index(i+1):] ,s-i). and if i is not a part of s then we have to form s from l[l.index(i+1):] list.
So it is similar in both the cases , only change is if i is part of s, then s=s-i and otherwise s=s only.
now to reduce the problem such that in case numbers in l are greater than s we remove them to reduce the complexity until l is empty and in that case the numbers which are selected are not a part of our solution and we return false.
if(len(b)==0):
return False
while(b[0]>n):
b.remove(b[0])
if(len(b)==0):
return False
and in case l has only 1 element left then either it can be part of s then we return true or it is not then we return false and loop will go through other number.
if(b[0]==n):
r.append(b[0])
return True
if(len(b)==1):
return False
note in the loop if have used b..but b is our list only.and i have rounded wherever it is possible, so that we should not get wrong answer due to floating point calculations in python.
r=[]
list_of_numbers=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]
list_of_numbers=sorted(list_of_numbers)
list_of_numbers.reverse()
sum_to_be_formed=401.54
def a(n,b):
global r
if(len(b)==0):
return False
while(b[0]>n):
b.remove(b[0])
if(len(b)==0):
return False
if(b[0]==n):
r.append(b[0])
return True
if(len(b)==1):
return False
for i in b:
if(a(round(n-i,2),b[b.index(i)+1:])):
r.append(i)
return True
return False
if(a(sum_to_be_formed,list_of_numbers)):
print(r)
this solution works fast.more fast than one explained above.
However this works for positive numbers only.
However also it works good if there is a solution only otherwise it takes to much time to get out of loops.
an example run is like this lets say
l=[1,6,7,8,10]
and s=22 i.e. s=1+6+7+8
so it goes through like this
1.) [10, 8, 7, 6, 1] 22
i.e. 10 is selected to be part of 22..so s=22-10=12 and l=l.remove(10)
2.) [8, 7, 6, 1] 12
i.e. 8 is selected to be part of 12..so s=12-8=4 and l=l.remove(8)
3.) [7, 6, 1] 4
now 7,6 are removed and 1!=4 so it will return false for this execution where 8 is selected.
4.)[6, 1] 5
i.e. 7 is selected to be part of 12..so s=12-7=5 and l=l.remove(7)
now 6 are removed and 1!=5 so it will return false for this execution where 7 is selected.
5.)[1] 6
i.e. 6 is selected to be part of 12..so s=12-6=6 and l=l.remove(6)
now 1!=6 so it will return false for this execution where 6 is selected.
6.)[] 11
i.e. 1 is selected to be part of 12..so s=12-1=1 and l=l.remove(1)
now l is empty so all the cases for which 10 was a part of s are false and so 10 is not a part of s and we now start with 8 and same cases follow.
7.)[7, 6, 1] 14
8.)[6, 1] 7
9.)[1] 1
just to give a comparison which i ran on my computer which is not so good.
using
l=[61.12,13.11,100.12,12.32,200,60.00,145.34,14.22,100.21,14.77,214.35,145.21,123.56,11.90,200.32,65.43,0.49,132.13,143.21,156.34,11.32,12.34,15.67,17.89,21.23,14.21,12,122,134]
and
s=2000
my loop ran 1018 times and 31 ms.
and previous code loop ran 3415587 times and took somewhere near 16 seconds.
however in case a solution does not exist my code ran more than few minutes so i stopped it and previous code ran near around 17 ms only and previous code works with negative numbers also.
so i thing some improvements can be done.
#!/usr/bin/python2
ylist = [1, 2, 3, 4, 5, 6, 7, 9, 2, 5, 3, -1]
print ylist
target = int(raw_input("enter the target number"))
for i in xrange(len(ylist)):
sno = target-ylist[i]
for j in xrange(i+1, len(ylist)):
if ylist[j] == sno:
print ylist[i], ylist[j]
This python code do what you asked, it will print the unique pair of numbers whose sum is equal to the target variable.
if target number is 8, it will print:
1 7
2 6
3 5
3 5
5 3
6 2
9 -1
5 3
I have found an answer which has run-time complexity O(n) and space complexity about O(2n), where n is the length of the list.
The answer satisfies the following constraints:
List can contain duplicates, e.g. [1,1,1,2,3] and you want to find pairs sum to 2
List can contain both positive and negative integers
The code is as below, and followed by the explanation:
def countPairs(k, a):
# List a, sum is k
temp = dict()
count = 0
for iter1 in a:
temp[iter1] = 0
temp[k-iter1] = 0
for iter2 in a:
temp[iter2] += 1
for iter3 in list(temp.keys()):
if iter3 == k / 2 and temp[iter3] > 1:
count += temp[iter3] * (temp[k-iter3] - 1) / 2
elif iter3 == k / 2 and temp[iter3] <= 1:
continue
else:
count += temp[iter3] * temp[k-iter3] / 2
return int(count)
Create an empty dictionary, iterate through the list and put all the possible keys in the dict with initial value 0.
Note that the key (k-iter1) is necessary to specify, e.g. if the list contains 1 but not contains 4, and the sum is 5. Then when we look at 1, we would like to find how many 4 do we have, but if 4 is not in the dict, then it will raise an error.
Iterate through the list again, and count how many times that each integer occurs and store the results to the dict.
Iterate through through the dict, this time is to find how many pairs do we have. We need to consider 3 conditions:
3.1 The key is just half of the sum and this key occurs more than once in the list, e.g. list is [1,1,1], sum is 2. We treat this special condition as what the code does.
3.2 The key is just half of the sum and this key occurs only once in the list, we skip this condition.
3.3 For other cases that key is not half of the sum, just multiply the its value with another key's value where these two keys sum to the given value. E.g. If sum is 6, we multiply temp[1] and temp[5], temp[2] and temp[4], etc... (I didn't list cases where numbers are negative, but idea is the same.)
The most complex step is step 3, which involves searching the dictionary, but as searching the dictionary is usually fast, nearly constant complexity. (Although worst case is O(n), but should not happen for integer keys.) Thus, with assuming the searching is constant complexity, the total complexity is O(n) as we only iterate the list many times separately.
Advice for a better solution is welcomed :)

Python: Binary Search - "Find the first occurrence"

having a bit of trouble with this one. I have included what I have below. When I submit it, it keeps saying "Program timed out" for some reason. I am not sure what to do next. It works to a certain degree, ie, some tests work, not the last test just doesn't work. What do you suggest?
I have included a screenshot of the question, as well as what I have so far.
Here is the note (pseudocode) from class, I just need to modify this to modify it to print the first occurance of the target in the ordered_list. If the target does not exist in the list, it must return None.
Thank you in advance!!
The Question:
You are to write the code of a Python function
binsearch first(ordered list, target)
that, given a nonempty ordered list of items and a target item, all of the same type, returns the index of the first occurrence of the target in the list, if the target is in the list, and None otherwise.
For example, the call binsearch first([1, 3, 3, 7, 9], 3) should return 1 since the first 3 is at index 1. Similarly, the call binsearch first([1, 3, 3, 7, 9], 9) should return 4, and the call binsearch first([1, 3, 3, 7, 9], 5) should return None.
You may not assume anything about the type of the items, other than that they are orderable. For example, items could be strings and the call binsearch first(["Alice", "Bob", "Chloe", "Chloe", "Dave"], "Chloe") should return 2.
Your program will be evaluated for efficiency and style. For full credit, it may only make a single test for equality (it may only have a single “==” comparison which, additionally, may not be within any loop). That is, the only equality test happens at the end of execution, just before returning.
Restrictions: Recursion is not allowed for this problem. allowed to use any operations other than
Furthermore, you are not
, − , // , × , < ,
and (once) ==
Of course, all builtins and library functions related to search are also disallowed: you have to do the coding yourself.
def binsearch_first(ordered_list, target):
left = 0
right = len(ordered_list) - 1
count = 0
while left <= right:
mid = (left + right) // 2
count = count + 1
if ordered_list[mid] == target:
while mid > 0 and ordered_list[mid - 1] == target:
mid = mid - 1
return mid
elif target < ordered_list[mid]:
right = mid - 1
else:
left = mid + 1
return None
Find the first occurrence
The only operator that works with string and integer is <.
We have to make use of the fact that it is an ordered list - arranged in increasing order.
def binsearch(orderedlist,target):
candidate = 0
for i in range(len(orderedlist)):
if orderedlist[i] < target:
candidate = candidate
else:
if i+1 < len(orderedlist):
if orderedlist[i] < orderedlist[i+1]:
#it is an ordered list so if i+1 is not bigger than i, it must be equal
candidate = candidate
else:
candidate = i
break # can you use break?
if orderedlist[candidate] == target:
return candidate
else:
return None
I am not a CS student hence cannot comment on the effectiveness of the program, but you can achieve your goal by using a simple for loop
def binsearch_first(ordered_list, target):
i=0
for ele in ordered_list:
if ele == target:
return i
break
else:
i+=1
return None
Result of this is:
>>> binsearch_first([1, 3, 3, 7, 9], 3)
1
>>> binsearch_first(["Alice", "Bob", "Chloe", "Chloe", "Dave"], "Chloe")
2
Regards

Finding minimum element in a list (recursively) - Python

I'm trying to find the minimum value in a list of integers using recursion. The main idea is that if the list is only one element long, this element is my minimum.
Else, I divide the list onto two smaller lists of the same size, look for minimum value in both of them and then compare which one is smaller.
The code looks like this:
def minimum(a,l,p):
if l == p:
return a[l]
else:
m1 = minimum(a,l, (l+p)/2)
m2 = minimum(a, (l+p)/2 + 1, p)
if m1 < m2:
return m1
else:
return m2
It doesn't seem to be difficult, however when I tried to run this function for a sample list, I got the following error: "RecursionError: maximum recursion depth exceeded in comparison".
Is something wrong with the algorithm or maybe I should look somewhere else for the reason fo this problem?
Your recursive strategy mentioned is similar a binary search, and it is most effected when traversing a tree to find a generic value as the tree is assumed to be structured in a sorted manner for maximum transversal efficiency. If you are truly intent on solving the problem with recursion, however, you can iterate over the list itself:
def minimum(l, val):
if not l[1:]:
return val
return minimum(l[1:], l[0] if l[0] < val else val)
l = [34, 23, 2, 4, 18]
print(minimum(l, l[0]))
Output:
2
In the end, I believe this is just an example on how to iterate through a list using recursion rather than using a loop and used for learning purposes. You can continuously split the list into halves until you get a list of length 1, which is when you surface the element. If you're doing this for learning purposes, I suggest you add print() statements to see what your list is doing.
def minimum(lst):
if len(lst) == 1:
return lst[0]
else:
m1 = minimum(lst[0:len(lst) / 2])
m2 = minimum(lst[len(lst) / 2:])
if m1 < m2:
return m1
else:
return m2
if __name__ == "__main__":
print(minimum([3, 4, 1, 2, 5]))
print(minimum([3, 2, 1, 0]))
But as #HFBrowning mentioned in a comment, in real life you should just use min(lst) and be done with it.
And as #PatrickHaugh mentioned in a comment to this answer, the division must return an integer. Which means, if you're running this on Python 3, you should change the len(lst) / 2 to len(lst) // 2 (see the double /?)
def RecursiveMin(L):
if len(L)==2:
if L[0]<L[1]:
return L[0]
else:
return L[1]
else:
X= RecursiveMin(L[1:])
if L[0]<X:
return L[0]
else:
return X
This formula will give you the smallest value in list.
L=[99,45,78,34,67,2,34,88]
RecursiveMin(L)
>>> 2

Find the largest sum of the maximal, compatible, values of two sorted arrays in sub quadratic time

Say I have two sorted lists like so:
a = [13, 7, 5, 3, 2, ..., 0]
b = [16, 12, 8, 4, ..., 1]
Also I have a function:
IsValid(x,y):
Which returns true if x and y are compatible. Compatibility completely arbitrary, except the value 0 is valid with any other number.
So how would i find the two numbers in a and b such that yield the greatest sum given they are both IsValid. Ie find the greatest valid sum.
Here is my current alg in Python
def FindBest(a, b):
isDone = False
aChecked =[]
bChecked = []
aPossible = []
aIndex = 0
bPossible = []
bIndex = 0
posResult = []
#initialize
try:
aPossible= (a[aIndex])
aIndex+=1
bPossible=(b[bIndex])
bIndex+=1
except:
print "Why did you run this on an empty list?"
return
while not isDone:
posResult = []
if(len(aPossible)>0):
for b in bChecked:
if(IsValid(aPossible,b)):
posResult.append(aPossible+b)
isDone = True
if len(bPossible)>0:
for a in aChecked:
if(IsValid(a,bPossible)):
posResult.append(a+bPossible)
isDone = True
#compare the first two possibles
if(IsValid(aPossible,bPossible)):
posResult.append(aPossible+bPossible)
isDone = True
if(len(aPossible) > 0):
aChecked.append(bPossible)
if(len(bPossible) >0):
bChecked.append(bPossible)
if(aIndex<len(a)):
aPossible= (a[aIndex])
aIndex+=1
if(bIndex<len(b)):
bPossible =(b[bIndex])
bIndex+=1
if len(a)==len(aChecked) and len(b) == len(bChecked):
print "none found"
isDone = True
return posResult
But as others has pointed out, the worst case of this is O(n*n) where n is the size of each list.
For a worst case example, consider a = [9,8,7,0] and b = [4,3,2,1] where there are no compatible pairs other than (0,4),(0,3),(0,2),(0,1).
Let's optimistically assume that you somehow checked and found these four pair first.
So you remembered that the pair (0,4) is the current-best answer.
You would still need to check all the pairs that are larger than size four to make sure that (0,4) really is the best answer.
To list those pairs:
(9,4)
(9,3) (8,4)
(9,2) (8,3) (7,4)
(9,1) (8,2) (7,3)
And the number of these pairs are growing O(n*n).
So it is impossible to deduce a sub quadratic time algorithm.
[Because I assume the best algorithm can be implemented, that algorithm still takes at least O(n*n) on some cases]
Maybe you left out some more information from your question?

Categories

Resources