comprehension with Nested loops - loops

I've to find how many different permutations are possible to create the sum of 65 using exactly three coins.
given list :
coins = [200, 100, 50, 20, 10, 5]
what I've tried so far:
len(set([x + y + z for x in coins for y in coins for z in coins if (x+y+z)%65 == 0]))
I've think I maybe should use the import function?
for example with a random list:
import itertools
len(list(itertools.permutations([1,2,3])))

Your nested loops approach technically doesn't actually solve the problem since it will over-count by including multiples of your target sum 65. You will need to count only those which are exactly 65 in order to solve the problem -- see here:
coins = [200, 100, 50, 20, 10, 5]
target = 65
original = len(set([x + y + z for x in coins for y in coins for z in coins if (x + y + z) % 65 == 0]))
print('Original:', original) # prints 3
new = list(set([x + y + z for x in coins for y in coins for z in coins if (x + y + z) % target == 0])).count(target)
print('Ignoring multiples of 65:', new) # prints 1
Now, for your second point, this is where it gets a little confusing. The above actually counts the number of combinations and not the number of permutations. In contrast, your original statement was for the number of permutations and your example with itertools also uses permutations. I'm not sure what your exact intention is, but itertools provides a method for both.
However, your example len(list(itertools.permutations([1, 2, 3]))) would return a count of all permutations rather than only those which sum to your target value. So, if you do len(list(itertools.permutations(coins))), the permutations would be of length 6 by default -- you have to supply a second argument to itertools.permutations for your target length of 3.
Hence, the following should work for you:
import itertools
perms = list(itertools.permutations(coins, 3)) # permutations of length 3
total_perms = len([perm for perm in perms if sum(perm) == target]) # count only those which sum to 65
print('Total permutations:', total_perms) # prints 6
However, if you actually were interested in the number of combinations -- which is what the original nested loops method does, then you would have to use itertools.combinations instead:
combs = list(itertools.combinations(coins, 3)) # combinations of length 3
total_combs = len([comb for comb in combs if sum(comb) == target]) # count only those which sum to 65
print('Total combinations:', total_combs) # prints 1
Good luck!

Related

Special Pairs in N natural number sequence

You are given a natural number N which represents sequence [1,2...N]. We have to determine the number of pairs (x,y) from this sequence that satisfies the given conditions.
1 <= x <= y <= N
sum of first x-1 numbers (i.e sum of [1,2,3..x-1]) = sum of numbers from x+1 to y (i.e sum of [x+1...y])
Example:-
If N = 3 there is only 1 pair (x=1,y=1) for which (sum of x-1 numbers) = 0 = (sum of x+1 to y)
any other pairs like (1,2),(1,3) or (2,3) does not satisfy the properties. so the answer is 1 as there is only one pair.
Another Example:-
If N=10, for pair (6,8) we can see sum of x-1 numbers i.e [1,2,3,4,5] = 15 = sum of numbers from x+1 to y i.e [7,8], Also another such pair would be (1,1). No other such pair exists so the answer, in this case, would be 2.
How can we approach and solve such problems to find the number of pairs in such a sequence?
Other things I have been able to deduce so far:-
Condition
Answer
Pairs
If 1<=N<=7
1
{(1,1)}
If 8<=N<=48
2
{(1,1),(6,8)}
If 49<=N<=287
3
{(1,1),(6,8),(35,49)}
If 288<=N<=1680
4
-
I tried but am unable to find any pattern or any such thing in these numbers.
Also, 1<=N<=10^16
--edit--
Courtesy of OEIS (link in comments): you can find the k'th value of y using this formula: ( (0.25) * (3.0+2.0*(2**0.5))**k ).floor
This gives us the k'th value in O(log k). First few results:
1
8
49
288
1681
9800
57121
332928
1940449
11309768
65918161
384199200
2239277041
13051463048
76069501249
443365544448
2584123765441
15061377048200
87784138523761
511643454094368
2982076586042447
17380816062160312
101302819786919424
590436102659356160
3441313796169217536
20057446674355949568
116903366249966469120
681362750825442836480
3971273138702690287616
23146276081390697054208
134906383349641499377664
786292024016458181771264
4582845760749107960348672
26710782540478185822224384
155681849482119992477483008
907380314352241764747706368
Notice that the ratio of successive numbers quickly approaches 5.828427124746. Given a value of n, take the log of n base 5.828427124746. The answer will be an integer close to this log.
E.g., say n = 1,000,000,000. Then log(n, 5.8284271247461) = 11.8. The answer is probably 12, but we can check the neighbors to be sure.
11: 65,918,161
12: 384,199,200
13: 2,239,277,041
Confirmed.
-- end edit --
Here's some ruby code to do this. Idea is to have two pointers and increment the pointer for x or y as appropriate. I'm using s(n) to calculate the sums, though this could be done without multiplication by just keeping a running total.
def s(n)
return n*(n+1)/2
end
def f(n)
count = 0
x = 1
y = 1
while y <= n do
if s(x-1) == s(y) - s(x)
count += 1
puts "(#{x}, #{y})"
end
if s(x-1) <= s(y) - s(x)
x += 1
else
y += 1
end
end
end
Here are the first few pairs:
(1, 1)
(6, 8)
(35, 49)
(204, 288)
(1189, 1681)
(6930, 9800)
(40391, 57121)
(235416, 332928)
(1372105, 1940449)
(7997214, 11309768)
(46611179, 65918161)

Maximize sum of array after applying the given operations on the array

Given an Array A consisting of N elements and an integer K. You can perform following operations on array any number of times(Can be 0).
Choose an element from array A. Let us denote as A[i]
Choose a positive integer Y.
Change A[i] to A[i] xor Y.
The Sum of all the Y's used in the operations should not be greater than K.
Your task is to find the maximum sum of all the elements of array A after operations.
Example:-
N=5
K=6
A={9,7,7,4,3}
Output:- 36
Explanation:- In the first operation, choose the fourth element and Y=2. Then change 4 to 4 xor 2, that is 6.
the updated array will be:- 9,7,7,6,3
In second Operation, choose the fifth element and Y=4. Then change 3 to 3 xor 4, that is 7.
The updated array will be 9,7,7,6,7
Hence sum is 36.
Please someone explain the logic behind the problem. I am not getting the idea.
Since you didn't clarify my comment about Y I will assume that the answer is no, you can not count unique Y values once towards the budget K.
This problem is simply a modified 0-1 knapsack problem in disguise. To solve it using the knapsack problem:
Let the item value & weight pairs be defined as the set
I = { (Y ^ a - a, Y) : a \in A, Y \in {1,K}}
Apply the dynamic programming solution to the 0-1 knapsack problem with weight limit K, and the requirement that only one item may be picked per a \in A. The total optimal weight of the knapsack problem + any unmodified a \in A is the solution.
Here is an implementation in python that solves the example given.
#!/usr/bin/python
def solve2(w,v,W,nK):
n = len(w)
m = dict()
for j in range(0,W+1):
m[-1, j] = 0
for i in range(-1,n):
m[i, 0] = 0
for i in range(0,n):
for j in range(0,W+1):
b_w = -1
b_v = -1
found = False
for k in range(0,nK):
if w[i][k] <= j and v[i][k] >= b_v:
b_w = w[i][k]
b_v = v[i][k]
found = True
if found:
m[i, j] = max(m[i-1, j], m[i-1, j-b_w] + b_v)
else:
m[i, j] = m[i-1, j]
return m[n-1,W]
A = [9,7,7,4,3]
K = 6
v = [ [ (Y^a)-a for Y in range(1,K+1) ] for a in A]
w = [ [ Y for Y in range(1,K+1) ] for a in A]
print ('Solution value is:', sum(A) + solve2(w,v,K,K))

Array Partition I (How to prove this in math)

This is a question from leetcode.
Given an integer array nums of 2n integers, group these integers into n pairs (a1, b1), (a2, b2), ..., (an, bn) such that the sum of min(ai, bi) for all i is maximized. Return the maximized sum.
Input: nums = [1, 4, 3, 2]
Output: 4
Explanation: All possible pairings (ignoring the ordering of elements) are:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
So the maximum possible sum is 4.
I resolved this by trying multiple examples and found out if I sorted and arranged the pair like 1 2 | 3 4, the min value of each pair is what I want. Since the array is sorted, the positions of min values are fixed; hence I can get the value by index + 2. Although it works, it's more like a guss. Does anyone know how to prove this in mathematics to make the logic more rigourously?
def arrayPairSum(nums: List[int]) -> int:
nums_sort = sorted(nums)
res = 0
i = 0
while i < len(nums):
res += nums_sort[i]
i += 2
return res
You can use induction. Let's say you have a sorted array a. The smallest number, a[0] will always be the smallest of whatever pair it occurs in. The maximum sum will occur if you select its partner to be a[1], the next smallest number. You can show this by selecting some other number a[m] to be its partner. In that case, at least one of the other pairs will have minimum a[1], which is by definition less than it would otherwise have. You can proceed to apply the same argument to the remaining elements a[2:].
Alternatively, you can start from the other end. a[-1] is guaranteed to never figure in the sum because it is the maximum of whatever pair it will occur in. If you pair it with anything other than a[-2], the total sum will not be maximized: some smaller a[m] will represent the pair containing a[-1] in the sum, while a[-2] will be larger than any a[n] it is paired with, and therefore will not appear in the sum.
Both arguments yield the same result: the maximum sum is over the even indices of the sorted array.
As mentioned in the comments, the following two implementations will be more efficient than a raw for loop:
def arrayPairSum(nums: List[int]) -> int:
return sum(sorted(nums)[::2])
OR
def arrayPairSum(nums: List[int]) -> int:
nums.sort()
return sum(nums[::2])
The latter does the sorting in-place, and is probably faster if allowed.

Fast Algorithm For Making Change With 6 Denominations: Interview Practice

I came to a solution for this problem, but it takes O(n^2). Is it possible to do better?
Problem: Suppose we want to make change for D dollars. We have an array A with N elements. The denominations exist within the array as dollar values, but we do not know the exact denominations in advanced. However, we are given that 0 < A[j] < 125*N. The restrictions are, we only have 6 of each type of denomination and we must be able to determine if we can give change using exactly 6 total bills (we can repeat bills and assume bills come in any type, so we can have 4$ bills)..
Ex:
If A = [3,4,6,5,20,18,10,30] and D = 50. Then the algorithm returns true since 5+5+5+5+10+20.
My attempts:
I tried sorting and then dividing but then I get stuck because I am not sure how to eliminate possible choices since I do not know exactly what is in the array. Better yet, without explicitly going through in O(n^2) time, I am not sure how to for sure say that it is not possible. Is it possible to take advantage of the fact that I know I am restricted to exactly 6 bills?
To me it looks like a typical recursion problem. Lets write a function that will check if we can make change for the D dollars. For that we will take the first bill (lets say it's $3), remove it from the the D and then recursively check if we can make change for the D - 3 dollars.
We can make this solution much faster if we don't check the combinations that we have already checked. So if we already know that bills 3, 5, 10 don't fit our needs then we don't need to check the combination 5, 10, 3 either. For that we need firstly to sort the A array and then pass the number of last used bill (last_bill_id) to the check function. Inside the function we don't need to check any combinations with bills with number less than last_bill_id.
Full solution in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
def check(counters, current_sum, depth, last_bill_id):
global A
if depth > 6: # max amount of bills is 6
return False
if depth == 6: # we used 6 bill, did we get the correct sum?
return current_sum == 0
if current_sum <= 0: # we gave too much change
return False
# current_sum > 0 and depth < 6
for i in xrange(last_bill_id, len(A)):
if counters[i] < 6:
# we can use i-th bill another time
counters[i] += 1
if check(counters, current_sum - A[i], depth + 1, i):
return True
counters[i] -= 1
return False
# init counters with zeros
counters = [0] * len(A)
# check if we can change for `D`
A = sorted(A) # sort A before the function
print 'Can make change:', check(counters, D, 0, 0)
# print bills with counters
for i, c in enumerate(counters):
if c > 0:
print '$%d x %d' % (A[i], c)
Output:
Can make change: True
$3 x 4
$18 x 1
$20 x 1
EDIT
Previous solution has complexity O(n^6). But actually we can make it even faster with memoization (or, we put it in the other way, dynamic programming). Lets sort the A array and repeat every number in it 6 times, so we'll get something like A = [3, 3, 3, 3, 3, 3, 5, 5, ...]. Now lets fill the 3D matrix M[,,], where M[bills_num, i, d] is true iff we can make change for the d dollars with bills_num bills starting in i-th position of the A array. The result will be in the cell M[6, 0, D]. This matrix has size 6 x (6 * n) x D, so we can fill it in O(6 * (6 * n) * D) == O(n * D) time (with the recursive approach similar to the solution before). Code in python:
A = [3, 4, 6, 5, 20, 18, 10, 30]
D = 50
# sort A and repeat 6 times
A = sorted(A * 6)
# create matrix M, where:
# 0 == uncomputed, 1 == True, -1 == False
arr1d = lambda x: [0] * x
arr2d = lambda x, y: [arr1d(y) for i in xrange(x)]
arr3d = lambda x, y, z: [arr2d(y, z) for i in xrange(x)]
M = arr3d(6 + 1, len(A), D + 1)
def fill_m(bills_num, start_pos, d):
global A, M
if d == 0: # can make change for 0 only with 0 bills
return True if bills_num == 0 else False
if d < 0 or bills_num <= 0 or start_pos >= len(A):
return False
if M[bills_num][start_pos][d] == 0:
# need to compute cell value
if fill_m(bills_num, start_pos + 1, d):
M[bills_num][start_pos][d] = 1
elif fill_m(bills_num - 1, start_pos + 1, d - A[start_pos]):
M[bills_num][start_pos][d] = 1
else:
M[bills_num][start_pos][d] = -1
return M[bills_num][start_pos][d] == 1
print 'Can make change for $', D, fill_m(6, 0, D)

How to generate a multiplicative space vector in Matlab?

I am trying to generate "automatically" a vector 0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30 (in multiplicative space).
I know linspace and logspace functions, but I couldn't find any similar function for multiplicative space.
Is there any? Otherwise, how to generate a vector like the one I need?
An easy way with bsxfun, also considering multiplication to smaller spaces:
x = [0.01,0.03,0.05] % initial vector, works for various lengths
n = 12; % times it should get multiplied in rising direction
m = 3; % times it should get multiplied in falling direction
Z = bsxfun( #times, x(:), 10.^(-m:n) )
Z = Z(:)
% if preferred, bulky one-liner:
% Z = reshape( bsxfun( #times, x(:), 10.^(-m:n) ) , 1 , [])
I assumed a multiplication with the multiplication vector, e.g.:
10.^(0:n) = 1 10 100 1000 10000 100000 ....
But custom vectors Y are also possible:
Z = bsxfun( #times, x(:), Y(:)' ) Z = Z(:)
A function that might help you achieving this in a very easy and compact way is the Kronecker tensor product kron.
You can use it to rewrite thewaywewalk's answer as:
v = [0.01;0.03;0.05]; % initial vector
emin = -3; % minimal exponent
emax = 12; % maximal exponent
Z = kron(10.^(emin:emax)',v(:))
which should give you the exact same result.
not very efficient but this will generate what you want. inputvec is your initial vector [0.01 0.03] in this case, multiplier is 10. length of the required string n is 8. n should be a multiple of nn (length of the input vector)
function newvec=multispace(n,inputvec,multiplier)
nn=length(inputvec);
newvec=zeros(1,n);
newvec(1:nn)=inputvec;
for i=1:n/nn-1
newvec(i*nn+1:(i+1)*nn)=(newvec((i-1)*nn+1:(i)*nn)).*multiplier;
end
end

Resources