Alright, so I have a small issue:
def common(a,b,c):
a.sort()
b.sort()
c.sort()
i = 0
j = 0
k = 0
common=False
while i<len(a) and j<len(b):
if a[i] == b[j]:
if b[j] == c[k]:
return True
else:
k = k+1
continue
else:
if i == len(a):
j = j+1
else:
i = i+1
return common
a=[3, 1, 5, 10]
b=[4, 2, 6, 1]
c=[5, 3, 1, 7]
print common(a,b,c)
Basically, it has to tell me if there are common elements in the lists. With 1 it works, but if I replace the 1's with 8's, it doesn't work anymore.
Your 'j' never increase, 1 is working because after sort it is the 1st element and doesn't need j to be increased.
My suggestion is convert your lists to sets and check the common elements using intersection(&)
def common(a,b,c):
common = set(a) & set(b) & set(c)
return True if common else False
a=[3, 8, 5, 10]
b=[4, 2, 6, 8]
c=[5, 3, 8, 7]
print common(a,b,c)
Your current algorithm only works if the smallest value in the b list is common to the other lists. If there's a different common value, you'll never find it, because you'll increment i until it is len(a), then quit.
I think you need to change your logic so that you increment the index of the list that points at the smallest value. If a[i] is less than b[j], you need to increment i. If c[k] is less still, you should increment it instead.
What you've programmed is not doing at all what you expect, so you need to rethink your logic. If you look at your loop, you first check if a[0] matches b[0]. Nope, so add to i. Then you compare a[1] to b[0], nope and so on. If nothing matches b[0], you exit the loop without ever checking the other elements of b. It works with 1's in your lists because after you sort, those happen to be in the first position in all three lists.
In any case, this is pretty clunky. There's a much easier way of doing this via set intersection. See this related question.
Related
I am looking for a least time-complex algorithm that would solve a variant of the perfect sum problem (initially: finding all variable size subset combinations from an array [*] of integers of size n that sum to a specific number x) where the subset combination size is of a fixed size k and return the possible combinations without direct and also indirect (when there's a combination containing the exact same elements from another in another order) duplicates.
I'm aware this problem is NP-hard, so I am not expecting a perfect general solution but something that could at least run in a reasonable time in my case, with n close to 1000 and k around 10
Things I have tried so far:
Finding a combination, then doing successive modifications on it and its modifications
Let's assume I have an array such as:
s = [1,2,3,3,4,5,6,9]
So I have n = 8, and I'd like x = 10 for k = 3
I found thanks to some obscure method (bruteforce?) a subset [3,3,4]
From this subset I'm finding other possible combinations by taking two elements out of it and replacing them with other elements that sum the same, i.e. (3, 3) can be replaced by (1, 5) since both got the same sum and the replacing numbers are not already in use. So I obtain another subset [1,5,4], then I repeat the process for all the obtained subsets... indefinitely?
The main issue as suggested here is that it's hard to determine when it's done and this method is rather chaotic. I imagined some variants of this method but they really are work in progress
Iterating through the set to list all k long combinations that sum to x
Pretty self explanatory. This is a naive method that do not work well in my case since I have a pretty large n and a k that is not small enough to avoid a catastrophically big number of combinations (the magnitude of the number of combinations is 10^27!)
I experimented several mechanism related to setting an area of research instead of stupidly iterating through all possibilities, but it's rather complicated and still work in progress
What would you suggest? (Snippets can be in any language, but I prefer C++)
[*] To clear the doubt about whether or not the base collection can contain duplicates, I used the term "array" instead of "set" to be more precise. The collection can contain duplicate integers in my case and quite much, with 70 different integers for 1000 elements (counts rounded), for example
With reasonable sum limit this problem might be solved using extension of dynamic programming approach for subset sum problem or coin change problem with predetermined number of coins. Note that we can count all variants in pseudopolynomial time O(x*n), but output size might grow exponentially, so generation of all variants might be a problem.
Make 3d array, list or vector with outer dimension x-1 for example: A[][][]. Every element A[p] of this list contains list of possible subsets with sum p.
We can walk through all elements (call current element item) of initial "set" (I noticed repeating elements in your example, so it is not true set).
Now scan A[] list from the last entry to the beginning. (This trick helps to avoid repeating usage of the same item).
If A[i - item] contains subsets with size < k, we can add all these subsets to A[i] appending item.
After full scan A[x] will contain subsets of size k and less, having sum x, and we can filter only those of size k
Example of output of my quick-made Delphi program for the next data:
Lst := [1,2,3,3,4,5,6,7];
k := 3;
sum := 10;
3 3 4
2 3 5 //distinct 3's
2 3 5
1 4 5
1 3 6
1 3 6 //distinct 3's
1 2 7
To exclude variants with distinct repeated elements (if needed), we can use non-first occurence only for subsets already containing the first occurence of item (so 3 3 4 will be valid while the second 2 3 5 won't be generated)
I literally translate my Delphi code into C++ (weird, I think :)
int main()
{
vector<vector<vector<int>>> A;
vector<int> Lst = { 1, 2, 3, 3, 4, 5, 6, 7 };
int k = 3;
int sum = 10;
A.push_back({ {0} }); //fictive array to make non-empty variant
for (int i = 0; i < sum; i++)
A.push_back({{}});
for (int item : Lst) {
for (int i = sum; i >= item; i--) {
for (int j = 0; j < A[i - item].size(); j++)
if (A[i - item][j].size() < k + 1 &&
A[i - item][j].size() > 0) {
vector<int> t = A[i - item][j];
t.push_back(item);
A[i].push_back(t); //add new variant including current item
}
}
}
//output needed variants
for (int i = 0; i < A[sum].size(); i++)
if (A[sum][i].size() == k + 1) {
for (int j = 1; j < A[sum][i].size(); j++) //excluding fictive 0
cout << A[sum][i][j] << " ";
cout << endl;
}
}
Here is a complete solution in Python. Translation to C++ is left to the reader.
Like the usual subset sum, generation of the doubly linked summary of the solutions is pseudo-polynomial. It is O(count_values * distinct_sums * depths_of_sums). However actually iterating through them can be exponential. But using generators the way I did avoids using a lot of memory to generate that list, even if it can take a long time to run.
from collections import namedtuple
# This is a doubly linked list.
# (value, tail) will be one group of solutions. (next_answer) is another.
SumPath = namedtuple('SumPath', 'value tail next_answer')
def fixed_sum_paths (array, target, count):
# First find counts of values to handle duplications.
value_repeats = {}
for value in array:
if value in value_repeats:
value_repeats[value] += 1
else:
value_repeats[value] = 1
# paths[depth][x] will be all subsets of size depth that sum to x.
paths = [{} for i in range(count+1)]
# First we add the empty set.
paths[0][0] = SumPath(value=None, tail=None, next_answer=None)
# Now we start adding values to it.
for value, repeats in value_repeats.items():
# Reversed depth avoids seeing paths we will find using this value.
for depth in reversed(range(len(paths))):
for result, path in paths[depth].items():
for i in range(1, repeats+1):
if count < i + depth:
# Do not fill in too deep.
break
result += value
if result in paths[depth+i]:
path = SumPath(
value=value,
tail=path,
next_answer=paths[depth+i][result]
)
else:
path = SumPath(
value=value,
tail=path,
next_answer=None
)
paths[depth+i][result] = path
# Subtle bug fix, a path for value, value
# should not lead to value, other_value because
# we already inserted that first.
path = SumPath(
value=value,
tail=path.tail,
next_answer=None
)
return paths[count][target]
def path_iter(paths):
if paths.value is None:
# We are the tail
yield []
else:
while paths is not None:
value = paths.value
for answer in path_iter(paths.tail):
answer.append(value)
yield answer
paths = paths.next_answer
def fixed_sums (array, target, count):
paths = fixed_sum_paths(array, target, count)
return path_iter(paths)
for path in fixed_sums([1,2,3,3,4,5,6,9], 10, 3):
print(path)
Incidentally for your example, here are the solutions:
[1, 3, 6]
[1, 4, 5]
[2, 3, 5]
[3, 3, 4]
You should first sort the so called array. Secondly, you should determine if the problem is actually solvable, to save time... So what you do is you take the last k elements and see if the sum of those is larger or equal to the x value, if it is smaller, you are done it is not possible to do something like that.... If it is actually equal yes you are also done there is no other permutations.... O(n) feels nice doesn't it?? If it is larger, than you got a lot of work to do..... You need to store all the permutations in an seperate array.... Then you go ahead and replace the smallest of the k numbers with the smallest element in the array.... If this is still larger than x then you do it for the second and third and so on until you get something smaller than x. Once you reach a point where you have the sum smaller than x, you can go ahead and start to increase the value of the last position you stopped at until you hit x.... Once you hit x that is your combination.... Then you can go ahead and get the previous element so if you had 1,1,5, 6 in your thingy, you can go ahead and grab the 1 as well, add it to your smallest element, 5 to get 6, next you check, can you write this number 6 as a combination of two values, you stop once you hit the value.... Then you can repeat for the others as well.... You problem can be solved in O(n!) time in the worst case.... I would not suggest that you 10^27 combinations, meaning you have more than 10^27 elements, mhmmm bad idea do you even have that much space??? That's like 3bits for the header and 8 bits for each integer you would need 9.8765*10^25 terabytes just to store that clossal array, more memory than a supercomputer, you should worry about whether your computer can even store this monster rather than if you can solve the problem, that many combinations even if you find a quadratic solution it would crash your computer, and you know what quadratic is a long way off from O(n!)...
A brute force method using recursion might look like this...
For example, given variables set, x, k, the following pseudo code might work:
setSumStructure find(int[] set, int x, int k, int setIdx)
{
int sz = set.length - setIdx;
if (sz < x) return null;
if (sz == x) check sum of set[setIdx] -> set[set.size] == k. if it does, return the set together with the sum, else return null;
for (int i = setIdx; i < set.size - (k - 1); i++)
filter(find (set, x - set[i], k - 1, i + 1));
return filteredSets;
}
I'm trying to make a vector adding of two arrays with the same dimensions, but all that I get is a "list index out of range" error. The code I used is:
x = [0, 0, 0]
y = [1, 2, 3]
i = 0
c = []
while (i <= len(x)):
c.append(a[i] + b[i])
i = i + 1
print c
Can you point me where is te problem? Any help or idea will be appreciated.
In python, try to avoid looping over indices when possible. A more pythonic way of doing this is the following list comprehension
c = [sum(items) for items in zip(x, y)]
list comprehensions allow you to operate on items in an iterable and return a list. zip allows you to iterate over multiple iterables at the same time. This is a good pattern to look out for as you keep learning python
You are iterating both the lists for following index values : [0,1,2,3].
As the length of both the lists is 3, iterating it upto index value 3, won't make any sense because index value begins from 0.
In the condition for while loop, you should change the condition from i <= len(x) to i < len(x).
I am trying to find out lowest unique element from list. I have been able to generate O(n^2) and O(n) solutions. But I don't find them optimized. Kindly help me understand,if there is a possible O(n) solution for it. No one liner solutions please. Below are my codes:
Main function:
if __name__ =="__main__":
print uniqueMinimum([6, 2, 6, -6, 45, -6, 6])
print lowestUnique([5, 10, 6, -6, 3, -6, 16])
O(n^2) Solution:
def lowestUnique(arr):
num = max(arr)
for i in range(len(arr)):
check = False
for j in range(len(arr)):
if arr[i]==arr[j] and i!=j:
check =True
if check==False:
if num > arr[i]:
num = arr[i]
return num
I would like to avoid using max(array) in above solution.
O(n) Solution:
def uniqueMinimum(array):
d ={}
a =[]
num = max(array)
for i in range(len(array)):
k =d.get(array[i])
if k is None:
d[array[i]] = 1
a.append(array[i])
else:
d[array[i]] = k+1
if array[i] in a:
a.remove(array[i])
a.sort()
return a[0]
I can't really comment on the big-O since it depends on the implementation of the built-in python functions which I've never looked into. Here's a more reasonable implementation though:
def lowestUnique(array):
for element in sorted(list(set(array))):
if array.count(element) == 1:
return element
raise Exception('No unique elements found.')
I have the following pseudocode.
for j in range(0, len(list)):
xx
xx
if something == True:
list.append("x")
Will range(0, len(list)) be called every time j iterates through the block of code, and hence will its max value update?
I tried figuring it out looking at the stack data, however I couldn't figure it out.
No, as range(0, len(list)) is created once at the beginning to create a list (or iterator in python 3), and then it is just iterated though (using next or indexing). It is equivalent to:
list_of_nums = range(0, len(list)) # [0, 1, 2, 3, ...]
for i in list_of_nums:
j = i[counter]
...
Use a while loop like:
j = 0
while j < len(list)):
xx
xx
if something == True:
list.append("x")
j += 1
The iterable is only evaluated once. Since range() on Python 2.x returns a fixed structure the iteration will never be modified once the looping has started. If you need the iteration to change then you will have to use something that doesn't return a fixed structure, such as iterating over the list itself.
range creates a list containing all the element between both arguments - there's nothing magical about it. Once the result is created, it is not modified if the parameters given to range are modified, just like any other function.
Assigning the value of len to a temporary variable will make this more obvious:
tempLen = len(list)
for j in range(0, tempLen):
xx
xx
if something == True:
list.append("x")
No. range is a built-in function. Calling it returns a list. The for statement holds the first return from range and then stops. Try the following:
l = ['a', 'b', 'c']
for j in range(0, len(l)):
l.append(j)
print j
It prints three lines.
BTW, it is not a good idea to assign a variable to list.
Not a homework question.
I was going through the questions here and I came across this question.
Someone has answered it. I have tried a lot to understand the recursion used but I am not able to get it. Could someone explain it to me?
Write a function, for a given number, print out all different ways to make this number, by using addition and any number equal to or smaller than this number and greater than zero.
For example, given a = 5, we have the following seven ways to make up 5:
1, 1, 1, 1, 1
1, 4
1, 1, 1, 2
1, 1, 3
2, 3
1, 2, 2
5
The solution from the site is in C++:
void printSeq( int num , int a[] , int len , int s )
{
if( num <= 0 )
{
for( int j = 0 ; j < len ; j++ )
cout << a[ j ] << "," ;
cout << endl;
return;
}
for(int i = s ; i <= num ; i++)
{
a[ len ] = i;
printSeq( num - i , a , len + 1 , i );
}
}
int main()
{
int a[5];
printSeq(5,a,0,1);
cin.get();
return 0;
}
When facing a problem like this it is often a good idea to take a step back from your editor/IDE and think about the problem by drawing out a simple case on a whiteboard. Don't even do pseudo-code yet, just draw out a flowchart of how a simple case (e.g. a = 3) for this problem would turtle all the way down. Also, don't worry about duplicate combinations at first. Try to find a solution which gives you all the desired combinations, then improve your solution to not give you duplicates. In this case, why not look at the manageable case of a = 3? Let me draw a little picture for you. A green checkmark means that we have arrived at a valid combination, a red cross means that a combination is invalid.
As you can see, we start with three empty subcombinations and then build three new subcombinations by appending a number to each of them. We want to examine all possible paths, so we choose 1, 2 and 3 and end up with [1], [2] and [3]. If the sum of the numbers in a combination equals 3, we have found a valid combination, so we can stop to examine this path. If the sum of the numbers in a combination exceeds 3, the combination is invalid and we can stop as well. If neither is the case, we simply continue to build combinations until we arrive at either a valid or invalid solution.
Since your question seems to be primarily about how to work out a recursive solution for this kind of problems and less about specific syntax and you just happened to find a C++ solution I am going to provide a solution in Python (it almost looks like pseudo code and it's what it know).
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
for number in range(1, a + 1): # try each number from 1 to a
if combosum + number <= a: # only proceed if we don't exceed a
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations c that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Let's test the code!
>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
...
[1, 1, 1]
[1, 2]
[2, 1]
[3]
This seems to work fine, another test for a = 5:
>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]
The solution includes all seven combinations we were looking for, but the code still produces duplicates. As you may have noticed, it is not necessary to take a number smaller than the previous chosen number to generate all combinations. So let's add some code that only starts to build an extcombo for numbers which are not smaller than the currently last number in a combination. If the combination is empty, we just set the previous number to 1.
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
lastnumber = combo[-1] if combo else 1 # last number appended
for number in range(lastnumber, a + 1): # try each number between lastnumber and a
if combosum + number <= a:
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Once again, let's test the code!
>>> combo = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 3]
[1, 2, 2]
[1, 4]
[2, 3]
[5]
The presented solution may not be the most efficient one that exists, but hopefully it will encourage you to think recursively. Break a problem down step by step, draw out a simple case for small inputs and solve one problem at a time.
Leaving the solution aside for moment and looking at the problem itself:
Compare this problem to insertion sort for an array(or any recursive algorithm). In insertion sort at any point during the execution we have a part of the array that is sorted and another part that is unsorted. We pick an element from the unsorted part and find it's place in the sorted part, thereby extending the sorted part, making the problem smaller.
In case of this problem, we have a fixed number of elements we can choose from i.e integers 1 to the number in the problem(let's call it N), to be a part of the sequence that sums up to N.
At any point we have collected some numbers that sum up to less than N(say X), reducing the problem to N-X size, also reducing our choices from 1..N to 1..(N-X) for the next recursion.
The solution does the obvious, making each choice from 1 to (N-X) and proceeding recursively till X=N. Every time the algorithm reaches X=N, means a permutation is found.
Note: One problem I see with the solution is that it needs to know the number of permutations that will be found beforehand.
int a[5];
This could cause problems if that value is unknown.