What is the fastest way to multiply different numbers by consecutive numbers? - python

My main goal is to make this code faster, like converting it to an equation or something else
 This code multiplies the digits of the number system with 'n' and the
digits size of 'l', and provided that there is no digit less than the digit to the left
For example:
If n = 3 and l = 2
The result will be 25 which is the product of multiplying the cells of these lists :
[1, 1]
[1, 2]
[1, 3]
[2, 2]
[2, 3]
[3, 3]
def plus(num_list,n,index):
if (num_list[0] == n and index == 0): return 0
if num_list[index] < n:
num_list[index]+=1
num_list = num_list[:index+1]+[num_list[index] for x in range((len(num_list)-1)-index)]
else:
return plus(num_list,n,index-1)
return num_list
while True:
n = int(input('n = '))
l = int(input('l = '))
rez = 0
num_list = [1 for x in range(l)]
while num_list:
print(num_list)
m = 1
for i in num_list:
m*=i
rez+= m
num_list = plus(num_list,n,l-1)
print(rez)

Changing the code a bit to print out 10 values for each l from 1 to 10 gives:
l=1: 1,3,6,10,15,21,28,36,45,55,
l=2: 1,7,25,65,140,266,462,750,1155,1705,
l=3: 1,15,90,350,1050,2646,5880,11880,22275,39325,
l=4: 1,31,301,1701,6951,22827,63987,159027,359502,752752,
l=5: 1,63,966,7770,42525,179487,627396,1899612,5135130,12662650,
l=6: 1,127,3025,34105,246730,1323652,5715424,20912320,67128490,193754990,
l=7: 1,255,9330,145750,1379400,9321312,49329280,216627840,820784250,2758334150,
l=8: 1,511,28501,611501,7508501,63436373,408741333,2141764053,9528822303,37112163803,
l=9: 1,1023,86526,2532530,40075035,420693273,3281882604,20415995028,106175395755,477297033785,
l=10: 1,2047,261625,10391745,210766920,2734926558,25708104786,189036065010,1144614626805,5917584964655,
These numbers can be looked up in the online encyclopedia of integer sequences. Which gives sequences such as A001296, A001297 and A001298. They have a description "Sterling numbers of the second kind S(n+l, n)". Which are referenced in Mathworld and Wikipedia.
Formulas for the first few l's:
l==1: n*(1+n)/2
l==2: n*(1+n)*(2+n)*(1+3*n)/24
l==3: n^2 (n + 1)^2 (n + 2) (n + 3) / 48
l==4: (n+4)*(n+3)*(n+2)*(n+1)*n *(15*n^3 + 30*n^2 + 5*n - 2)/5760
PS: Sympy, Python's symbolic math library, has a function stirling to calculate its values. It only works with fixed integers, not with symbolic variables.
from sympy.functions.combinatorial.numbers import stirling
n = int(input('n = '))
l = int(input('l = '))
print(stirling(n+l, l))
for l in range(1, 11):
print([stirling(n+l,n) for n in range(1,21)])
The formula at Wikipedia can also be written using more basic sympy functions.
def s(n, k):
return Sum(((-1) ** (k - i)) * binomial(k, i) * i ** n / factorial(k), (i, 0, k)).doit()

Related

1d array or 2d array when solving dynamic programming problems

My question is how can you identify when to use a 1d array or 2d array for a dynamic programming problem. For instance, I stumbled upon the problem number of ways to make change
Here is an example:
inputs n = 12 and denominations = [2, 3, 7],
suppose you can pick an unlimited (infinite) amount of coins of each of the denominations you have. In how many ways can you make change for 12. The answer is 4
I got to the answer using dynamic programming and here is my code
def numberOfWaysToMakeChange(n, denoms):
if n == 0 or len(denoms) == 0:
return 1
ways = [[0 for _ in range(n + 1)] for _ in range(len(denoms))]
for row in ways:
row[0] = 1
for i in range(n + 1):
if i % denoms[0] == 0:
ways[0][i] = 1
for i in range(1, len(denoms)):
for j in range(1, n + 1):
if denoms[i] > j:
ways[i][j] = ways[i - 1][j]
else:
ways[i][j] = ways[i - 1][j] + ways[i][j - denoms[i]]
return ways[-1][-1]
result = numberOfWaysToMakeChange(12, [2, 3, 7])
print(result)
But online I found an answer that works as well that looks like the following
ways = [0 for _ in range(n + 1)]
ways[0] = 1
for denom in denoms:
for amount in range(1, n+1):
if denom <= amount:
ways[amount] += ways[amount - denom]
return ways[n]
How can you identify when you can use a 1d array for these kind of questions?

Stuck in writing python list reduction program

I am stuck in writing the python code for below problem, can anyone help to find the issue with the code is much appreciated.
List Reduction:
You are given a list of integers L having size N and an integer K. You can perform the following operation on the list at most k times:
Pick any two elements of the list.
Multiply any element by 2.
Divide the other element by 2, taking the ceiling if element is odd.
Note: that after such an operation, the list is changed and the changed list will be used in subsequent operations.
You need to minimize the sum of all elements present in the list after performing at most k such operations.
Input Format:
First line contains N K as described above.
The second line contains N space separated integers, representing the list initially,
Output Format:
Print the minimum possible sum of all elements in the list at the end, after performing at most k operations.
Code:
def solve (X, arr):
Sum = 0
largestDivisible, minimum = -1, arr[0]
for i in range(0,N):
Sum += arr[i]
if(arr[i]%X == 0 and largestDivisible < arr[i]):
largestDivisible = arr[i]
if arr[i] < minimum:
minimum = arr[i]
if largestDivisible == -1:
return Sum
sumAfterOperation = (Sum-minimum-largestDivisible+(X*minimum)+(largestDivisible//X))
return min(Sum,sumAfterOperation)
N=5
X =2
#map(int, input().split())
arr = [10, 7, 4, 2, 1]
#list(map(int, input().split()))
out_ = solve(X, arr)
print (out_)
output: 20
expected output: 19
Not optimal program.
Idea: Multiplying the minimal element and dividing the maximal element gives sequence with minimal total sum. Do you want process negative numbers? Does K take negative values?
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
arr.sort()
arr[0] *= 2
arr[-1] = arr[-1] // 2 + arr[-1] % 2
print(sum(arr))
More effective solution.
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
mn, mx = min(arr), max(arr)
mn_i = arr.index(mn)
if mn != mx:
mx_i = arr.index(mx)
else:
mx_i = arr.index(mx, mn_i+1)
arr[mn_i] *= 2
arr[mx_i] = arr[mx_i] // 2 + arr[mx_i] % 2
print(sum(arr))
And algorithmic solution.
K = int(input())
arr = list(map(int, input().split()))
for _ in range(K):
mn, mx = 0, 0
for i, x in enumerate(arr):
if x < arr[mn]:
mn = i
if x >= arr[mx]:
mx = i
arr[mn] *= 2
arr[mx] = arr[mx] // 2 + arr[mx] % 2
print(sum(arr))

How can I collect pairs of numbers from multiples inputs, then print them all at once at the end?

I have several inputs that will general outputs that are pairs of numbers. And I want to collect these pairs and print them out at the end.
e.g.
first input() produces ->
2 3
4 6
5 9
29 99
33 12
second input() produces ->
4 5
9 9
44 5
third input() produces ->
5 5
9 9
10 10
And instead of printing the output of the three individual inputs, I want to store them somewhere, then print once the inputs have finished running.
Is there anyway to use yield/generator? Because I am conscious that we have multiple inputs and this will not work. Will it work if I run the generator for each input?
Otherwise, would I need to store the pair of integers in an array perhaps?
Input Format
The first line of input contains a single integer T
, denoting the number of test cases. The description of T
test cases follows.
Each testcase consists of a single line of input, containing two integers N,M ; the number of vertices and edges of the graph you must construct.
Here is my code, although I think it is only the last batch that is relevant:
from collections import defaultdict
T = int(input())
for _ in range(T):
N, M = map(int, input().split())
arrayOfNodes = [i for i in range(1, N + 1)]
numberOfBridges = N - 1
edgesLeft = M - (N - 1)
# building number of edges left- to determine max # of briges we can achieve
bridgeBurn = defaultdict(int)
bridgeBurn[1] = -2
count = -2
for edge in range(2, N):
count -= 1
m = (edge * (edge + 1)) // 2
bridgeBurn[m] = count
# determine how many bridges to burn
bridgesToBurn = 0
for topInterval in bridgeBurn:
if topInterval== edgesLeft:
bridgesToBurn = bridgeBurn[topInterval]
break
elif topInterval > edgesLeft:
bridgesToBurn = bridgeBurn[topInterval]+1
break
finalNumberOfBridges = numberOfBridges + bridgesToBurn
for edge in range(1, len(arrayOfNodes)):
print(f"{arrayOfNodes[0]} {arrayOfNodes[edge]}")
if M == N-1:
continue
elif M > N - 1:
while edgesLeft>0:
for edge in range(2, N+1 - finalNumberOfBridges):
for edge2 in range(edge + 1, N+1 - finalNumberOfBridges):
print(f"{edge} {edge2}")
edgesLeft -= 1
In your functions, use return [x, y] (where x and y are lists of what you were printing -> edge and edge2 or arrayOfNodes and arrayOfNodes2) just to make it easier to store.
So the simplified problem would be something like:
def input1():
return [[1, 2, 3], [4, 5, 6]]
...
I'm just going to put out the code for storing the returned variables here:
It could probably be made less of an eyesore but it works perfectly
def imp1():
return [[1, 2, 3], [4, 5, 6]]
def imp2():
return [["a", 'b', 'c'], ['z', 'y', 'x']]
def imp3():
return [[0, 1, 2, 3], [3, 2, 1, 0]]
val = []
for i in [imp1, imp2, imp3]:
[x, y] = i()
val += [[x, y]]
print(val)
for i in val:
for j, k in i, val[val.index(i) + 1]:
for l in range(len(k)):
print(j[l], k[l])

Find a maximum possible value of an array

I have an array of integers and I need to get their maximum possible value. If I have negative numbers and their total amount is uneven I have to exclude one of them to make an array positive.
If I have 0 inside and it can affect on result of my multiplication, I have to exclude it also.
For example: for [2, 5, -2] result should be 10, for [-2,-5,-1, 0, 2] result should be 20.
I implemented the task, but the system doesn't accept my solution, could you please take a look at my solution where I could make a mistake? I tried different edge cases like [-1], [1], [0], [0,0,0]
def answer(n):
arr = 0
res = 1
for number in n:
if number < 0:
arr += 1
n.sort()
while 0 in n: n.remove(0)
if not n:
return '0'
if len(n) == 1:
if n[0] < 0:
return '0'
elif arr % 2 != 0:
n.pop(arr - 1)
for x in n:
res *= x
return str(res)
It appears you are looking to multiply all numbers in a list, except for any zeroes and if there's an odd number of negative numbers, you are excluding the smallest negative number?
A simple solution:
from functools import reduce
def answer(numbers):
selection = [n for n in numbers if n != 0]
negative = [n for n in selection if n < 0]
if len(negative) % 2 == 1:
selection.remove(max(negative))
if not selection:
return 0
else:
return reduce(lambda x, y: x * y, selection)
print(answer([-2, -5, -1, 0, 2]))

Making a list of a geometric progression when the ratio and range are given

Given the positive integer ratio greater than 1, and the non-negative integer n, create a list consisting of the geometric progression of numbers between (and including) 1 and n with a common ratio of ratio. For example, if ratio is 2 and n is 8, the list would be [1, 2, 4, 8].
Associate the list with the variable geom_prog.
I have tried the following code:
r= ratio
geom_prog = []
for i in range(1, n+1):
i *= r
geom_prog.append(i)
For ratio 2 and n = 8:
Expected result: [1, 2, 4, 8]
What I got: [2, 4, 6, 8, 10, 12, 14, 16]
More than anything I'm just wondering what the correct algorithm for getting the correct elements would be. Or if there is a more efficient way to do this problem.
If I understand
r = 2 # set here the factor
geom_prog = []
x = 1 # first element and var to update
n = 8 # last element
for i in range(x, n+1):
geom_prog.append(x)
x *= r
EDIT:
Or more pythonic
[start * ratio**i for i in range(n)]
ref: Python: Generate a geometric progression using list comprehension
r = ratio
geom_prog = []
x = 1
while x <= n:
geom_prog.append(x)
x *= r
The problem is instead of restricting values till 8,
for i in range(1, n+1):
this is telling the program to run the loop for n times.
try this instead:
n = 8
r = 2
geom_prog = []
i = 1 ;
while(i*r <= n):
geom_prog.append(i*r)
i+=1 ;
#print(geom_prog) #returns [2, 4, 6, 8]
Use a simple while loop:
>>> r = 2
>>> n = 8
>>> e = 1
>>> geom_prog = []
>>> while e <= n:
... geom_prog.append(e)
... e *= r
...
>>> geom_prog
[1, 2, 4, 8]
A few good answers have already been posted, but adding this one as well.
you can use the math library to calculate the for loop upper limit as well as each element in the progression without changing your logic too much.
import math
r= 2
geom_prog = []
n = 8
n = int(math.log(n, r))
for i in range(0, n+1):
k = math.pow(r,i)
geom_prog.append(k)
Suppose you want to know how many terms will be involved in advance.
Think of the following question, we want ratio^m <= n where we want to solve for m.
then we have m <= log(n)/log(ratio), since m is an integer, m <= int(log(n)/log(ratio))
import math
n=8
ratio = 2
r= ratio
geom_prog = [1]
for i in range(1, int(math.log(n)/math.log(ratio))+1):
geom_prog.append(geom_prog[-1] * r)
print(geom_prog)
By looping over range(1, n+1), you're making n passes (8 in your case). The termination criteria you're looking for is when the newest element of your set hits (or exceeds) n. Try a while loop:
>>> def geom(ratio, n):
... series = [1]
... while series[-1] < n:
... series.append( series[-1] * ratio )
... return series
...
>>>
>>> geom(2, 8)
[1, 2, 4, 8]
Probably want to add some code to check this will terminate for your parameters (e.g. a ratio of 1 with n > 1 will never terminate), but this should get you started.

Categories