Partitions of k parts with minimum and maximum part values - python

How do I generate the partitions of a number that have exactly k parts, where each part has a minimum and maximum value?
For example, If I want to select all partitions of 21 with 6 parts with minimum part value 3 and the maximum part value is 6, I should get the following partitions:
[3, 3, 3, 3, 3, 6]
[3, 3, 3, 3, 4, 5]
[3, 3, 3, 4, 4, 4]
I have the following ascending partition code, courtesy of http://jeromekelleher.net/generating-integer-partitions.html
def accel_asc(n):
a = [0 for i in range(n + 1)]
k = 1
y = n - 1
while k != 0:
x = a[k - 1] + 1
k -= 1
while 2 * x <= y:
a[k] = x
y -= x
k += 1
l = k + 1
while x <= y:
a[k] = x
a[l] = y
yield a[:k + 2]
x += 1
y -= 1
a[k] = x + y
y = x + y - 1
yield a[:k + 1]
and a simple fuction I wrote to only get the partitions I want from the function above:
def eligible_partitions(list_of_partitions, min_value, max_value, k):
l = []
for x in list_of_partitions:
if min(x) >= min_value and max(x) <= max_value and len(x) == k:
l.append(x)
return l
Instead of having to generate and loop through all of the partitions of a particular value, I only want to generate those that meet the specified criteria.

Here is one way to do it:
def part(x, n, minval, maxval):
if not n * minval <= x <= n * maxval:
return
elif n == 0:
yield []
else:
for val in range(minval, maxval + 1):
for p in part(x - val, n - 1, val, maxval):
yield [val] + p
for p in part(21, 6, 3, 6):
print p
This produces:
[3, 3, 3, 3, 3, 6]
[3, 3, 3, 3, 4, 5]
[3, 3, 3, 4, 4, 4]

Related

Find the sum of two arrays

I am trying to find the sum of two lists/arrays in Python.
For example:
You are given with two random integer lists as lst1 and lst2 with size n and m respectively. Both the lists contain numbers from 0 to 9(i.e. single digit integer is present at every index).
The idea here is to represent each list as an integer in itself of digits N and M.
You need to find the sum of both the input list treating them as two integers and put the result in another list i.e. output list will also contain only single digit at every index.
Following is the code which I have tried:
def list_sum(lst1, n, lst2, m) :
i, j, sum, carry = 0, 0, 0, 0
new_lst = []
if n == 0 and m == 0:
new_lst.append(0)
elif n > 0 and m>0:
while n > 0 and m > 0:
sum = lst1[n - 1] + lst2[m - 1] + carry
if sum >= 10:
carry = 1
else:
carry = 0
new_lst.append(sum % 10)
n -= 1
m -= 1
while n > 0:
if (lst1[n-1] + carry) >= 10:
new_lst.append((lst1[n-1] + carry) % 10)
carry = 1
else:
new_lst.append(lst1[n-1])
carry = 0
n -= 1
while m > 0:
if (lst2[m-1] + carry) >= 10:
new_lst.append((lst2[m-1] + carry) % 10)
carry = 1
else:
new_lst.append(lst1[m-1])
carry = 0
m -= 1
if carry == 1:
new_lst.append(1)
new_lst.reverse()
elif n == 0 and m > 0:
new_lst.append(0)
new_lst = new_lst + lst2
elif n > 0 and m == 0:
new_lst.append(0)
new_lst = new_lst + lst1
print(new_lst)
however I feel I am missing something here and which is not giving me proper answer for the combination. Sometimes it errors list out of index error. I don't know why.
The example input:
n = 3
lst1 = [6, 9, 8]
m = 3
lst2 = [5, 9, 2]
output:
[1, 2, 9, 0]
Here, each element is summed and then if the sum >=10 then we get a carry = 1 and which will be added with the next sum.
i.e
1. 8+2= 10 >=10 hence carry=1 in first sum
2. 9+9+1( carry) = 19 >=10 hence carry=1
3. 6+5+1( carry) = 12>=10 hence carry=1
4. upend the carry to next position as 1
Hence resultant list would be [1, 2, 9, 0]
What can I try next?
Well, all other answers are awesome for adding 2 numbers (list of digits).
But in case you want to create a program which can deal with any number of 'numbers',
Here's what you can do...
def addNums(lst1, lst2, *args):
numsIters = [iter(num[::-1]) for num in [lst1, lst2] + list(args)] # make the iterators for each list
carry, final = 0, [] # Initially carry is 0, 'final' will store the result
while True:
nums = [next(num, None) for num in numsIters] # for every num in numIters, get the next element if exists, else None
if all(nxt is None for nxt in nums): break # If all numIters returned None, it means all numbers have exhausted, hence break from the loop
nums = [(0 if num is None else num) for num in nums] # Convert all 'None' to '0'
digit = sum(nums) + carry # Sum up all digits and carry
final.append(digit % 10) # Insert the 'ones' digit of result into final list
carry = digit // 10 # get the 'tens' digit and update it to carry
if carry: final.append(carry) # If carry is non-zero, insert it
return final[::-1] # return the fully generated final list
print(addNums([6, 9, 8], [5, 9, 2])) # [1, 2, 9, 0]
print(addNums([7, 6, 9, 8, 8], [5, 9, 2], [3, 5, 1, 7, 4])) # [1, 1, 2, 7, 5, 4]
Hope that makes sense!
If I understand correctly you want it like this:
[6, 9, 8], [5, 9, 2] -> 698 + 592 = 1290 -> [1, 2, 9, 0]
In that case my first idea would be to turn the numbers into strings, combine them to one string
and turn it into an int, then add both values together and turn into a list of integers again...
you can try this:
def get_sum_as_list(list1, list2):
first_int = int(''.join(map(str,list1)))
second_int = int(''.join(map(str,list2)))
result = [int(num) for num in str(first_int+second_int)]
return result
Here's one possible solution:
(i) join each list to create a pair of string representation of integers
(ii) convert them to integers,
(iii) add them,
(iv) convert the sum to string
(v) separate each digit as ints
def list_sum(lst1, lst2):
out = []
for i, lst in enumerate([lst1, lst2]):
if len(lst) > 0:
out.append(int(''.join(str(x) for x in lst)))
else:
if i == 0:
return lst2
else:
return lst1
return [int(x) for x in str(out[0]+out[1])]
list_sum([6,9,8],[5,9,2])
Output:
[1, 2, 9, 0]
Two other answers show solutions repeatedly converting between lists of int and strings and ints. I think this is a bit cheating and completely hides the algorithm.
Here I present a solution that manipulates the lists of ints directly to build a third list of ints.
from itertools import chain, repeat # pad list with 0 so they are equal size
from operator import add # add(x,y) = x+y
def padded(l1, l2):
"padded([1, 2, 3], [1, 2, 3, 4, 5]) --> [0, 0, 1, 2, 3], [1, 2, 3, 4, 5]"
padded1 = chain( repeat(0, max(0, len(l2)-len(l1))), l1 )
padded2 = chain( repeat(0, max(0, len(l1)-len(l2))), l2 )
return padded1, padded2
def add_without_carry_same_size(l1, l2):
"add_without_carry([6, 9, 8], [5, 9, 2]) --> [11, 18, 10]"
return map(add, l1, l2)
def flatten_carry(l):
"flatten_carry([11, 18, 10]) --> [1, 2, 9, 0]"
c = 0
for i in range(len(l)-1, -1, -1):
c, l[i] = divmod(c + l[i], 10)
if c > 0:
l[:] = [c] + l
def list_add(l1, l2):
'''
list_add([6, 9, 8], [5, 9, 2]) --> [1, 2, 9, 0]
list_add([9, 9, 9, 9, 9], [1]) --> [1, 0, 0, 0, 0, 0]
'''
p1, p2 = padded(l1, l2)
l3 = list(add_without_carry_same_size(p1, p2))
flatten_carry(l3)
return l3
Relevant documentation:
builtin function map;
itertools.chain;
itertools.repeat;
operator.add;
builtin function divmod.
Tried the following logic
def list_sum(lst1, n, lst2, m, output):
i, j, k, carry = n - 1, m - 1, max(n, m), 0
while i >= 0 and j >= 0:
output[k] = (lst1[i] + lst2[j] + carry) % 10
carry = (lst1[i] + lst2[j] + carry) // 10
i = i - 1
j = j - 1
k = k - 1
while i >= 0:
output[k] = (lst1[i] + carry) % 10
carry = (lst1[i] + carry) // 10
i = i - 1
k = k - 1
while j >= 0:
output[k] = (lst2[j] + carry) % 10
carry = (lst2[j] + carry) // 10
j = j - 1
k = k - 1
output[0] = carry
print(output)
where the output parameter in the above code it taken from below
outputSize = (1 + max(n, m))
output = outputSize * [0]
and called the function
list_sum(lst1, n, lst2, m, output)
You don't mention how long your lists will be. So considering they aren't going to be that long (anyway, python can handle bignums), why not making a simple sum operation? In the end that's what the code should emulate.
import numpy as np
lst1 = [6, 9, 8]
lst2 = [5, 9, 2]
lst1_len = len(lst1)
lst2_len = len(lst2)
if lst1_len >= lst2_len:
lst2 = [0] * (lst1_len - lst2_len) + lst2
else:
lst1 = [0] * (lst2_len - lst1_len) + lst1
common_len = len(lst1)
lst1_val = sum(np.array(lst1) * np.array([10**(-x) for x in range(-common_len + 1, 1)]))
lst2_val = sum(np.array(lst2) * np.array([10**(-x) for x in range(-common_len + 1, 1)]))
total = lst1_val + lst2_val
total_as_list = [int(x) for x in str(total)]
where
print(total_as_list)
[1, 2, 9, 0]
Code:
def addNums(*args):
nums=[]
for i in args:
if i:
i = list(map(str,i)) # Converts each element int to string['6', '9', '8'] , ['5', '9', '2']
add=int(''.join(i)) # Joins string and convert to int 698 ,592
nums.append(add) # Appends them to list [698, 592]
Sum = str(sum(nums)) # Sums the values and convert to string '1290'
result=list(map(int,Sum)) # Converts to list with each converted to int[1,2,9,0]
return result
print(addNums([6, 9, 8], [5, 9, 2]))
print(addNums([7, 6], [5, 9], [3, 5],[7, 4]))
print(addNums([]))
Output:
[1, 2, 9, 0]
[2, 4, 4]
[0]

How can I count the number of cases in recursive functions?

def calcPath(trace_map, x, y):
n = len(trace_map)
count = 0
if x > n - 1 or y > n - 1:
pass
elif x < n and y < n:
if x + trace_map[x][y] == (n - 1) and y == (n - 1):
count += 1
elif x == (n - 1) and y + trace_map[x][y] == (n - 1):
count += 1
else:
calcPath(trace_map, x + trace_map[x][y], y)
calcPath(trace_map, x, y + trace_map[x][y])
return count
if __name__ == "__main__":
trace_map = [
[1, 2, 9, 4, 9],
[9, 9, 9, 9, 9],
[9, 3, 9, 9, 2],
[9, 9, 9, 9, 9],
[9, 9, 9, 1, 0],
]
print(calcPath(trace_map, 0, 0))
trace_map = [[1, 1, 1], [1, 1, 2], [1, 2, 0]]
print(calcPath(trace_map, 0, 0))
I want to count the existing routes of the given maze. (anyway, the problem itself is not that important)
Problem is, I tried to count the number of cases that fit the conditions within the recursive functions.
These are two conditions that have to be counted.
if x + trace_map[x][y] == (n - 1) and y == (n - 1):
if x == (n - 1) and y + trace_map[x][y] == (n - 1):
I tried counting the conditions like this
count = 0
if condition = True:
count +=1
But since I'm using recursive functions, if I declare count = 0 in the function, the count value stays 0.
Shortly, I just want to keep the counter unaffected by the recursive function.
One of the ways to solve this is by adding the count you get from each recursive function's return. When you call the recursive function, take the count that is returned and add it to the count variable in the current scope. For example:
def calcPath(trace_map, x, y):
n = len(trace_map)
count = 0
if x > n - 1 or y > n - 1:
pass
elif x < n and y < n:
if x + trace_map[x][y] == (n - 1) and y == (n - 1):
count += 1
elif x == (n - 1) and y + trace_map[x][y] == (n - 1):
count += 1
else:
count += calcPath(trace_map, x + trace_map[x][y], y)
count += calcPath(trace_map, x, y + trace_map[x][y])
return count
An alternative solution would be to create a global variable and reset it to 0 every time the function is called (although I don't recommend this since it requires ceremony everytime the function is called).
That might look something like this:
count = 0 # Global variable
def calcPath(trace_map, x, y):
global count
n = len(trace_map)
if x > n - 1 or y > n - 1:
pass
elif x < n and y < n:
if x + trace_map[x][y] == (n - 1) and y == (n - 1):
count += 1
elif x == (n - 1) and y + trace_map[x][y] == (n - 1):
count += 1
else:
calcPath(trace_map, x + trace_map[x][y], y)
calcPath(trace_map, x, y + trace_map[x][y])
if __name__ == "__main__":
trace_map = [
[1, 2, 9, 4, 9],
[9, 9, 9, 9, 9],
[9, 3, 9, 9, 2],
[9, 9, 9, 9, 9],
[9, 9, 9, 1, 0],
]
print(calcPath(trace_map, 0, 0))
# Use count in some way
count = 0 # Reset the count
trace_map = [[1, 1, 1], [1, 1, 2], [1, 2, 0]]
print(calcPath(trace_map, 0, 0))
I think you can use the concept of nested scope or put it simply function inside another function. For example:
def fuc(args):
if not args:
return 0
else:
fuc.count += 1
return args[0] + fuc(args[1:])
def fac(fuc, args):
fuc.count = 0
return fuc(args), fuc.count
print(fac(fuc, [1, 2, 3]))
print(fac(fuc, [4, 5, 6, 7]))
(6, 3)
(22, 4)
[Finished in 0.1s]

How to write a function which calculates product of even elements in the list from n to m position in python?

This is what I have tried already, but it only shows me two values, I want to see all even values in that interval, is that possible?
eL = [8, 2, 4, 5, 6, 10]
m = []
n = []
for x in eL:
if x % 2 == 0 and x == eL[0]:
m.append(x)
for x in eL:
if x % 2 == 0 and x == eL[4]:
n.append(x)
print(m, n)
For example,
For the list [8, 2, 4, 5, 6,10]
and n = 1 and m = 3
the result should be 2 · 4
And for n = 0, m = 3
the result should be 8 · 2 · 4
And for n = 2, m = 4 it should be 4 · 6.
Here is the code:
eL = [8, 2, 4, 5, 6, 10]
m = 1
n = 3
result = []
for x in eL:
if x % 2 == 0 and (eL.index(x) >= m and eL.index(x) <= n):
result.append(x)
print(result)
You can use .index and >=, <=
Or (thanks to the comment by Tal J. Levy)
eL = [8, 2, 2, 4, 5, 6, 10]
m = 1
n = 3
result = []
for x in eL[m:n+1]:
if x % 2 == 0:
result.append(x)
print(result)
Just loop it around like this: for x in eL[m:n+1]:
Product of even numbers from n to m indexes:
>>> from functools import reduce
>>> from operator import mul
>>> n, m = 1, 4
>>> lst = [1, 2, 3, 4, 5]
>>> sublst = lst[n:m]
>>> evens = [i for i in sublst if i % 2 == 0]
>>> reduce(mul, evens, 1)
8

Number of subarrays within a sum range

Question
Given an array of non negative integers A, and a range (B, C),
find the number of continuous subsequences in the array which have sum S in the range [B, C] or B <= S <= C
Continuous subsequence is defined as all the numbers A[i], A[i + 1], .... A[j]
where 0 <= i <= j < size(A)
Example :
A : [10, 5, 1, 0, 2]
(B, C) : (6, 8)
ans = 3
[5, 1], [5, 1, 0], [5, 1, 0, 2] are the only 3 continuous subsequence with their sum in the range [6, 8]
My Code
def numRange(A, B, C):
n = len(A)
count = 0
for i in xrange(n-1):
newsum = A[i]
j = i + 1
while newsum <= C and j < n:
if newsum >= B :
count += 1
newsum += A[j]
j += 1
if A[n-1] >= B and A[n-1] <= C:
count += 1
return count
Problem : Wrong Answer.
What are the cases I am missing ?
How do I improve the efficiency of this code after rectifying it ?
The strategy I used was to effectively buffer the results, until I got to the end, then process the remainder of the buffer. This therefore requires at most, two iterations, or O(n) time.
EDIT: Removed calls to sum():
def numRange(A, B, C):
current = []
current_sum = 0
count = 0
for number in A:
current.append(number)
current_sum += number
while current_sum > C:
current_sum -= current[0]
current = current[1:]
if B <= current_sum <= C:
count += 1
print current_sum, current
# Now check the remaining items in current, in case of a trailing sequence:
# Test with A = [10, 5, 1, 0, 2, 4] to demonstrate the need.
if not current:
return count
current_sum -= current[0]
current = current[1:]
while (B <= current_sum <= C):
count += 1
print current_sum, current
current_sum -= current[0]
current = current[1:]
return count
print "Total of %d subarrays" % numRange( [10, 5, 1, 0, 2], 6, 8)
print
print "Total of %d subarrays" % numRange( [10, 5, 1, 0, 2, 4], 6, 8)
Output:
6 [5, 1]
6 [5, 1, 0]
8 [5, 1, 0, 2]
Total of 3 subarrays
6 [5, 1]
6 [5, 1, 0]
8 [5, 1, 0, 2]
7 [1, 0, 2, 4]
6 [0, 2, 4]
6 [2, 4]
Total of 6 subarrays
Got it to obey
def numRange(A, B, C):
n = len(A)
sets = []
for i in range(n):
sum = 0
j = i
while sum < B and j < n:
sum += A[j]
j += 1
while sum >= B and sum <= C and j <= n:
if sum <= C:
sets.append(A[i:j])
if j < n:
sum += A[j]
j += 1
return sets
sets = numRange([10, 5, 1, 0, 2], 6, 8)
print len(sets) # 3
print sets # [[5, 1], [5, 1, 0], [5, 1, 0, 2]]
The issue with your code is for the [5, 1, 0, 2] case. You compute the sum which is equal to 8. Then increment j to 5
newsum += A[j] # newsum was 6, add A[4] = 2, now 8
j += 1
but then the loop is exited as j now equals 5, failing the j < n condition. So the increment of count never happens for this sum. Unfortunately just switching the order of the things in the inner loop isn't sufficient to fix it.
This is my O(n^2) worst case solution. With O(1) extra space. Can anyone give better solution than this in O(n)
class Solution:
def numRange(self, A, B, C):
count = 0
end = len(A)-1
tot = 0
temp_sum = 0
temp_array = []
tot_sum = sum(A[0:len(A)])
for i in range(len(A)):
current_sum = 0
for j in range(i,len(A)):
current_sum += A[j]
if(current_sum > C):
break
elif(B <= current_sum <= C):
#print current_sum
tot += 1
tot_sum -= A[i]
if(tot_sum < B):
break
return tot

Find overlap of two lists, preserving sequence order

I've found many methods of finding list intersections here, but I'm having trouble finding an efficient way to find the intersection when order is taken into account.
list1 = [1, 2, 3, 4, 5, 6, 7]
list2 = [7, 6, 3, 4, 5, 8]
The function should return [3, 4, 5]
I would already know there is only one overlapping sequence, and I would know its minimum length, but not its exact length.
You are looking for the Longest Common Subsequence algorithm; the following uses dynamic programming to find the elements in O(NM) time (for sequences of length N and M):
def lcs(a, b):
tbl = [[0 for _ in range(len(b) + 1)] for _ in range(len(a) + 1)]
for i, x in enumerate(a):
for j, y in enumerate(b):
tbl[i + 1][j + 1] = tbl[i][j] + 1 if x == y else max(
tbl[i + 1][j], tbl[i][j + 1])
res = []
i, j = len(a), len(b)
while i and j:
if tbl[i][j] == tbl[i - 1][j]:
i -= 1
elif tbl[i][j] == tbl[i][j - 1]:
j -= 1
else:
res.append(a[i - 1])
i -= 1
j -= 1
return res[::-1]
Demo:
>>> def lcs(a, b):
... tbl = [[0 for _ in range(len(b) + 1)] for _ in range(len(a) + 1)]
... for i, x in enumerate(a):
... for j, y in enumerate(b):
... tbl[i + 1][j + 1] = tbl[i][j] + 1 if x == y else max(
... tbl[i + 1][j], tbl[i][j + 1])
... res = []
... i, j = len(a), len(b)
... while i and j:
... if tbl[i][j] == tbl[i - 1][j]:
... i -= 1
... elif tbl[i][j] == tbl[i][j - 1]:
... j -= 1
... else:
... res.append(a[i - 1])
... i -= 1
... j -= 1
... return res[::-1]
...
>>> list1 = [1, 2, 3, 4, 5, 6, 7]
>>> list2 = [7, 6, 3, 4, 5, 8]
>>> lcs(list1, list2)
[3, 4, 5]
This will find the subsequence regardless of location and if other elements are mixed in between:
>>> lcs([1, 2, 3, 4, 5, 6, 7], [7, 3, 6, 4, 8, 5])
[3, 4, 5]

Categories

Resources