How to retrieve subset in partitioning algorithm? - python

I have an array and I would like to split it two parts such that their sum is equal for example [10, 30, 20, 50] can be split into [10, 40] , [20, 30]. Both have a sum of 50. This is essentially partitioning algorithm but I'd like the retrieve the subsets not just identify whether it's partitionable. So, I went ahead and did the following:
Update: updated script to handle duplicates
from collections import Counter
def is_partitionable(a):
possible_sums = [a[0]]
corresponding_subsets = [[a[0]]]
target_value = sum(a)/2
if a[0] == target_value:
print("yes",[a[0]],a[1:])
return
for x in a[1:]:
temp_possible_sums = []
for (ind, t) in enumerate(possible_sums):
cursum = t + x
if cursum < target_value:
corresponding_subsets.append(corresponding_subsets[ind] + [x])
temp_possible_sums.append(cursum)
if cursum == target_value:
one_subset = corresponding_subsets[ind] + [x]
another_subset = list((Counter(a) - Counter(one_subset)).elements())
print("yes", one_subset,another_subset)
return
possible_sums.extend(temp_possible_sums)
print("no")
return
is_partitionable(list(map(int, input().split())))
Sample Input & Output:
>>> is_partitionable([10,30,20,40])
yes [10, 40] [30, 20]
>>> is_partitionable([10,30,20,20])
yes [10, 30] [20, 20]
>>> is_partitionable([10,30,20,10])
no
I'm essentially storing the corresponding values that were added to get a value in corresponding_subsets. But, as the size of a increases, it's obvious that the corresponding_subsets would have way too many sub-lists (equal to the number of elements in possible_sums). Is there a better/more efficient way to do this?

Though it is still a hard problem, you could try the following. I assume that there are n elements and they are stored in the array named arr ( I assume 1-based indexing ). Let us make two teams A and B, such that I want to partition the elements of arr among teams A and B such that sum of elements in both the teams is equal. Each element of arr has an option of either going to team A or team B. Say if an element ( say ith element ) goes to team A we denote it by -a[i] and if it goes to team B we let it be a[i]. Thus after assigning each element to a team, if the total sum is 0 our job is done. We will create n sets ( they do not store duplicates ). I will work with the example arr = {10,20,30,40}. Follow the following steps
set_1 = {10,-10} # -10 if it goes to Team A and 10 if goes to B
set_2 = {30,-10,10,-30} # four options as we add -20 and 20
set_3 = {60,0,20,-40,-20,-60} # note we don't need to store duplicates
set_4 = {100,20,40,-40,60,-20,-80,0,-60,-100} # see there is a zero means our task is possible
Now all you have to do is backtrack from the 0 in the last set to see if the ith element a[i] was added as a[i] or as -a[i], ie. whether it is added to Team A or B.
EDIT
The backtracking routine. So we have n sets from set_1 to set_n. Let us make two lists list_A to push the elements that belong to team A and similarly list_B. We start from set_n , thus using a variable current_set initially having value n. Also we are focusing at element 0 in the last list, thus using a variable current_element initially having value 0. Follow the approach in the code below ( I assume all sets 1 to n have been formed, for sake of ease I have stored them as list of list, but you should use set data structure ). Also the code below assumes a 0 is seen in the last list ie. our task is possible.
sets = [ [0], #see this dummy set it is important, this is set_0
#because initially we add -arr[0] or arr[0] to 0
[10,-10],
[30,-10,10,-30],
[60,0,20,-40,-20,-60],
[100,20,40,-40,60,-20,-80,0,-60,-100]]
# my array is 1 based so ignore the zero
arr = [0,10,20,30,40]
list_A = []
list_B = []
current_element = 0
current_set = 4 # Total number of sets in this case is n=4
while current_set >= 1:
print current_set,current_element
for element in sets[current_set-1]:
if element + arr[current_set] == current_element:
list_B.append(arr[current_set])
current_element = element
current_set -= 1
break
elif element - arr[current_set] == current_element:
list_A.append(arr[current_set])
current_element = element
current_set -= 1
break
print list_A,list_B

This is my implementation of #sasha's algo on the feasibility.
def my_part(my_list):
item = my_list.pop()
balance = []
temp = [item, -item]
while len(my_list) != 0:
new_player = my_list.pop()
for i, items in enumerate(temp):
balance.append(items + new_player)
balance.append(items - new_player)
temp = balance[:]
balance = set(balance)
if 0 in balance:
return 'YES'
else:
return 'NO'
I am working on the backtracking too.

Related

How to add the last two elements in a list and add the sum to existing list

I am learning Python and using it to work thru a challenge found in Project Euler. Unfortunately, I cannot seem to get around this problem.
The problem:
Even Fibonacci numbers
Each new term in the Fibonacci sequence is generated by adding the
previous two terms. By starting with 1 and 2, the first 10 terms will
be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not
exceed four million, find the sum of the even-valued terms.
I created a for loop that adds the second to last element and the last element from the list x:
x = [1,2]
for i in x:
second_to_last = x[-2]
running_sum = i + second_to_last
If you run the above, you get 3. I am looking to add this new element back to the original list, x, and repeat the process. However, each time I try to use the append() function, the program crashes and keeps on running without stopping. I tried to use a while loop to stop this, but that was a complete failure. Why am I not able to add or append() the new element (running_sum) back to the original list (x)?
UPDATE:
I did arrive at the solution (4613732), but I the work to getting there did not seem efficient. Here is my solution:
while len(x) in range(1,32):
for i in x:
second_to_last = x[-2]
running_sum = i + second_to_last
x.append(running_sum)
print(x)
new_x = []
for i in x:
if i%2 == 0:
new_x.append(i)
sum(new_x)
I did have to check the range to see visually whether I did not exceed 4 million. But as I said, the process I took was not efficient.
If you keep adding elements to a list while iterating over that list, the iteration will never finish.
You will need some other criterion to abort the loop - for example, in this case
if running_sum > 4000000:
break
would work.
(Note that you don't strictly speaking need a list at all here; I'd suggest experimenting a bit with it.)
Here are two different ways to solve this. One of them builds the whole list, then sums the even elements. The other one only keeps the last two elements, without making the whole list.
fib = [1,2]
while fib[-1] < 4000000:
fib.append(fib[-2]+fib[-1])
# Get rid of the last one, since it was over the limit.
fib.pop(-1)
print( sum(i for i in fib if i % 2 == 0) )
fib = (1,2)
sumx = 2
while True:
nxt = fib[0]+fib[1]
if nxt >= 4000000:
break
if nxt % 2 == 0:
sumx += nxt
fib = (fib[1],nxt)
print(sumx)
I don't answer your question about list modification but the solution for your problem:
def sum_even_number_fibonacci(limit):
n0 = 0 # Since we don't care about index (n-th), we can use n0 = 0 or 1
n1 = 1
even_number_sum = 0
while n1 <= limit:
if n1 % 2 == 0:
even_number_sum += n1
n2 = n0 + n1
# Only store the last two number of the Fibonacci sequence to calculate the next one
n0 = n1
n1 = n2
return even_number_sum
sum_even_number_fibonacci(4_000_000)

Finding the Kth Largest element in a Python List using recursion

Given an input list that contains some random unsorted numbers, I am trying to write a program that outputs the kth largest distinct element in that list. For example:
Input:
el = [10,10, 20,30,40, 40]
k = 2
Output: 30 #Since 30 is the second largest distinct element in the list
The following function, takes as input a list, the pivot Index and k and populates list "lesser" with all elements lesser than the pivot and populates another list "greater" with all elements greater than the pivot.
Now, looking at the length of the two list, I can determine if the kth largest element is in the lesser list or the greater list. Now I recursively call the same function. However, my program's output is wrong for certain values of k.
def kthLargest(el, pivotIndex, k):
pivot = el[pivotIndex]
lesser = [] #List to store all elements lesser than pivot
greater = [] #Lsit to store all elements greater than pivot
equals = [] #List to store all elements equal to pivot
for x in el:
if x > pivot:
greater.append(x)
elif x < pivot:
lesser.append(x)
else:
equals.append(x)
g = len(greater) #Length of greater list
l = len(lesser)
if(g == k - 1): #If greater list has k-1 elements, that makes the pivot kth largest element
return pivot
elif(g < k):
return kthLargest(lesser, l - 1, k) #If greater list is smaller than k, kth largest element is in lesser list
else:
return kthLargest(greater, g - 1, k) #Else kth largest element is in greater list
Is there any reason you want to use recursion? To find the kth largest element of a list you have to look through the entire list, so the problem is essentially O(n) complexity anyway.
You could do this without recursion like this:
el = [10, 10, 53, 20, 30, 40, 59, 40]
k = 2
def kth_largest(input_list, k):
# initialize the top_k list to first k elements and sort descending
top_k = input_list[0:k]
top_k.sort(reverse = True)
for i in input_list[k:]:
if i > top_k[-1]:
top_k.pop() # remove the lowest of the top k elements
top_k.append(i) # add the new element
top_k.sort(reverse = True) # re-sort the list
return top_k[-1] # return the kth largest
kth_largest(el, k)
Here is a simple solution:
def kthmax(k, list):
if (k == 1):
return max(list)
else:
m = max(list)
return(kthmax(k-1, [x for x in list if x != m]))
kthmax(3,[4, 6, 2, 7, 3, 2, 6, 6])
Output: 4
There's an easy way to do this problem using recursion. I'm just not sure why you need the pivot in the problem description... For example:
def find_kth(k, arr):
if k == 1:
return max(arr)
m = max(arr)
new_arr = list(filter(lambda a: a != m, arr))
return(find_kth(k-1, new_arr))
If we can pass in a list or series that is already sorted in descending
order, e.g
el.sort_values(ascending=False, inplace = True)
then you can easily find the kth largest (index,value) tuple
using just simple slicing of sorted dataframe column and/or list
def kth_largest(input_series, k):
new_series = input_series[k-1:len(input_series)]
return (np.argmax(new_series) , np.max(new_series))
el = pd.Series([10, 10, 53, 20, 30, 40, 59, 40])
print el
k = 2
el.sort_values(ascending=False, inplace=True)
print kth_largest(el, 2)
Output: 30
0 10
1 10
2 53
3 20
4 30
5 40
6 59
7 40
dtype: int64
(2, 53)
Algorithm: Take the index of max value and convert to zero.
def high(arr,n):
for i in range(n+ 1 ):
arr[arr.index(max(arr))] = 0
return max(arr)
high([1,2,3,4,5], 2)
My way of finding the Kth largest element is...
lst=[6,2,3,4,1,5]
print(sorted(lst,reverse=True)[k-1])
On top of S Rohith Kumar's answer, If the input has duplicate values, then the answer can be :
print(sorted(set(lst),reverse=True)[k-1])

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?

Manually sort a list of 10 integers in python

I'm fairly new to programming; I've only been studying Python for a few weeks. I've been given an exercise recently that asks me to generate a list of integers, and then manually sort the numbers from lowest to highest in a separate list.
import random
unordered = list(range(10))
ordered = []
lowest = 0
i = 0
random.shuffle(unordered)
lowest = unordered[0]
while i in unordered:
if unordered[i] < lowest:
lowest = unordered[i]
i += 1
if i >= len(unordered):
i = 0
ordered.append(lowest)
unordered.remove(lowest)
lowest = unordered[i]
print(ordered)
This is what I have so far, and to be quite frank, it doesn't work at all. The pseudocode I have been given is this:
Create an empty list to hold the ordered elements
While there are still elements in the unordered list
Set a variable, lowest, to the first element in the unordered list
For each element in the unordered list
If the element is lower than lowest
Assign the value of that element to lowest
Append lowest to the ordered list
Remove lowest from the unordered list
Print out the ordered list
The biggest issue I'm having so far is that my counter doesn't reliably give me a way to pick out the lowest number from my list unordered. And then I'm having issues with indexing my list i.e. the index being out of range. Can anyone give me a bit of feedback on where I'm going wrong?
Also, I was given this info which I'm not really sure about:
You can use an established method to sort the list called the Selection Sort.
I'm not supposed to be using Python's built in sort methods this time around. It's all supposed to be done manually. Thanks for any help!
You can do this without having to create another list.
x = [5, 4, 3, 2, 5, 1]
n = len(x)
# Traverse through all list elements
for i in range(n):
# Traverse the list from 0 to n-i-1
# (The last element will already be in place after first pass, so no need to re-check)
for j in range(0, n-i-1):
# Swap if current element is greater than next
if x[j] > x[j+1]:
x[j], x[j+1] = x[j+1], x[j]
print(x)
This works with duplicates and descending lists. It also includes a minor optimization to avoid an unnecessary comparison on the last element.
Note: this answer and all the others use bubble sort, which is simple but inefficient. If you're looking for performance, you're much better off with another sorting algorithm. See which is best sorting algorithm and why?
You've just got some of the order wrong: you need to append to your ordered list each time around
import random
unordered = list(range(10))
ordered = []
i = 0
random.shuffle(unordered)
print unordered
lowest = unordered[0]
while len(unordered) > 0:
if unordered[i] < lowest:
lowest = unordered[i]
i += 1
if i == len(unordered):
ordered.append(lowest)
unordered.remove(lowest)
if unordered:
lowest = unordered[0]
i = 0
print(ordered)
you're not supposed to create a new algorithm for sorting list, just implement this one :
http://en.wikipedia.org/wiki/Bubble_sort
I found this is working pretty well for any number of inputs
x = [3, 4, 100, 34, 45]
for i in range(len(x) - 1):
if x[i] > x[i + 1]:
x[i],x[i + 1] = x[i + 1], x[i]
print (x)
Above code won't work if you have repetitive elements.
ordered=[]
i=0
j=0
x = [100, 3, 4, 100, 34, 45]
lowest=x[0]
while len(x)>0:
for i in range(0,len(x)):
if x[i]<=lowest:
lowest=x[i]
ordered.append(lowest)
x.remove(lowest)
if len(x)>1:
lowest=x[0]
print(ordered)
def sort(x):
l=len(x)
for i in range(l):
for j in range((i+1),l):
if x[i]>x[j]:
l1=x[i]
x[i]=x[j]
x[j]=l1
print(x)
l=[8,4,2,6,5,1,12,18,78,45]
sort(l)
From the first number in the list, run a loop to find the lowest value. After that swap them with the first number in the list. Repeat this loop method for remaining numbers in the list.
nlist=[int(a) for a in input('Please insert your list of numbers ').split()]
for loop1 in range (0,len(nlist)-1): # outer loop
min=nlist[loop1]
for loop2 in range (loop1 + 1,len(nlist)): # inner loop to compare
if min > nlist[loop2]:
min=nlist[loop2]
index=loop2
if nlist[loop1] != min:
swap=nlist[loop1]
nlist[loop1]=min
nlist[index]=swap
print('Your hand-sorted list is',nlist)

Probability Algorithm

I have a problem of probability algorithm
The goal is obtain a list which contains three items. as the FinalList
There has Four source lists.
ALIST, BLIST, CLIST, DLIST
There are all Unknown length. They contains unique elements
( In fact, there are all empty at the program beginning, get from redis sorted list. when running, there growing )
Choose items form this source lists. pick up random items to generate the FinalList
Ensure The Following Requirements
In the FinalList,
probability of ALIST's item appeared is 43%
probability of BLIST's item appeared is 37%
probability of CLIST's item appeared is 19%
probability of DLIST's item appeared is 1%
I have written some code, but this just for the four lists are have a lots of elements.
from random import choice
final_list = []
slot = []
a_picked_times = 0
while a_picked_times < 43:
item = choice(ALIST)
ALIST.remove(item)
if item in already_picked_list:
continue
slot.append(item)
a_picked_times += 1
b_picked_times = 0
while b_picked_times < 37:
...
SOME CODE SIMILAR
# now slot is a list which contains 100 elements,
# in slot, there are 43 elements of ALIST'items, 37 of B, 19 of C, 1 of D
for i in range(3):
final_list.append( choice(slot) )
So, this can ensure the probability requirements. BUT only under the condition: this Four lists have a lots of elements.
list.remove( item ) that will not remove all elements in list, so we will correct pick up items with the needs times.
when A, B, C, D empty OR not enough elements, How could ensure the probability requirements?
A, B, C, D list are all get from redis sorted list. Or some solution with redis ?
It might make more sense to (for each element) pick a number between 1 and 100 and then select a source list based on that.
As I understand it, you're generating lists of random sizes, then you want to choose 3 with the given probability. If my understanding is correct, then you need to simply generate a uniform variate on [0,1] with random.uniform(0., 1.).
Then simply partition the 0..1 interval into the appropriate lengths:
import random
for i in range(3):
r = random.uniform(0., 1.)
if r < .43:
final_list.append(random.choice(ALIST))
elif r < .43 + .37:
final_list.append(random.choice(BLIST))
elif r < .43 + .37 + .19:
final_list.append(random.choice(CLIST))
else:
final_list.append(random.choice(DLIST))
Choosing from the lists should be easy, since you just pick an index.
Note that this is equivalent to Ofir's answer, but may or may not appeal to you more.
So from what I can gather, your code is removing exactly 43 ALIST elements, 37 BLIST elements, etc.
A better solution would be to construct your final_list by using the given probabilities. This will also take into account when your other lists are empty.
ALIST_PROB = 0.43
BLIST_PROB = ALIST_PROB + 0.37
CLIST_PROB = BLIST_PROB + 0.19
DLIST_PROB = CLIST_PROV + 0.01
while len(final_list) < 3:
#generate a random number
rand = random.random()
if rand <= ALIST_PROB:
element = getEl(ALIST)
elif rand <= BLIST_PROB:
element = getEl(BLIST)
elif rand <= CLIST_PROB:
element = getEl(CLIST)
elif rand <= DLIST_PROB:
element = getEl(DLIST)
if not element == None:
final_list.append(element)
def getEl(list):
try:
element = random.choice(list)
except IndexError:
element = None
return element

Categories

Resources