The sequence is:
an = an-1 + (2 * an-2)
a0 = 1, a1= 1. Find a100
The way I did it is making a list.
#List 'a' with a0 = 1 , a1 = 1.
a = [1,1]
#To get the a100, implement 'i' as the index value of the list.
for i in range (2,101):
x = a[i-1] + (2 * a[i-2])
print( str(len(a)) + (": ") + str(x))
#Save new value to list
a.append(x)
Is there another way to do this where you can just directly get the value of a100? Or the value of a10000.. it will take up so much memory.
For this specific case, the sequence appears to be known as the Jacobsthal sequence. Wikipedia gives a closed form expression for a_n that can be expressed as follows:
def J(n):
return (2**(n+1) - (1 if n % 2 else -1))//3
Slightly more generally, you can use fast matrix exponentiation to find a specific value of a_n in O(log n) matrix operations. The approach here is a slight modification of this.
import numpy as np
def a(n):
mat = np.array([[1, 2], [1, 0]], dtype=object) # object for large integers
return np.linalg.matrix_power(mat, n)[0,0]
Here is the value for a_1000:
7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
This recurrence relation has a closed form solution:
a = lambda n: (2**(n+1) + (-1)**n)//3
Then
a(0) == 1
a(1) == 1
a(2) == 3
...
Use Wolfram Alpha solve for the closed form solution.
For a more general solution, sympy's rsolve can generate a formula for linear recurrences. And then use substitution to find particular values.
from sympy import rsolve, Function, symbols
f = Function('f')
n = symbols('n', integer=True)
T = f(n) - f(n - 1) - 2 * f(n - 2)
sol = rsolve(T, f(n), {f(0): 1, f(1): 1})
print(sol.factor())
for k in range(6):
print(f'a[{10**k}] = {sol.subs({n:10**k})}')
This finds the formula: ((-1)**n + 2*2**n)/3 and substituting various values gives:
a[1] = 1
a[10] = 683
a[100] = 845100400152152934331135470251
a[1000] = 7143390714575115472989500327066678737076032078036890716291669255802340340832907483287989192104639054183964486117020978834580968571282093623989718383132383202623045183216153990280716403374914094585302788102030983322387960844932511706110362630718041943047464318457694778440286554435082924558137112046251
a[10000] = 13300420779205055899224947751223900558823312212574616365680059665686292553481297754613307789357463065266220752948806082847704327566275854078395857288064215971903820031195863017843497700844039930347033391278795541028339072307078736457006049910726416592060326596558672835961088838567081045539649268371274925376816731095916294031173247751323635481912358774462877183753093841891253840488152356727760984122637587639312975932940560640357511880709747618222262691017043766353735428453489979600223956211100972865182186443850404115054687605329465453071585497122508186691535256991501267222976387636433705286400943222614410489725426171396919846079518533884638490449629415374679171890883668485549192847140249201910928687618755494267749463781127049374279769561549759200832570764870138287994839741197500087328573494472227205070621546774178994858997503894208562707691159300991409504210074059830342802209213468621093971730976504006937230561044048029975244677676707947087336124281517272447267049737611904634607637370045500833604005013228174598706158078702963192048604263495032226147988471602982108251173897742022519137359868942131422329103081800375446624970338827853981873988860876269047918349845673238184625284288814399599917924440538912558558685095521850114849105048496522741529593155873907738282168861316542080131736118854643798317265443020838956090639908522753418790270855651099392460347365053921743882641323846748271362887055383912692879736402269982104388805781403942200602501882277026496929598476838303527006808207298214407168983217160516849324232198998893837958637097759081249712999519344381402467576288757211476207860932148655897231556293513976121900670048618498909700385756334067235325208259649285799693889564105871362639412657210097186118095746465818754306322522134720983321447905340926047485500603884544957480384983947611769143791817076603055269994974019086721023722205420067991783904156229025970272783748933896591684108429045765889012975813584862160062970831282169566933785351515891836917604484599090827358327607311145704700506065400164526586785514617302254188281302685535172938965970009784445593131997924161090875584262602248970534271757827918474036922817159666073457645479797721100990086996148246631809842046103645478455250800241851505149187576887740797874187195112987924800865762440512367759907023068198581038345298256830912964615391929510632144672034080214910330858779357159414245558929061170945822567007313514409276959727327732103102944890874437957354081499958646666151187821572015407908429716866090505450005466559490856410166587392640154829574782514412057571343645656039081553195235917082324370960357975081345975714019208241045008362225535513352731779100379038105003677818345932796086474225126766610787543447696005152433715459704967280220123536564742545543604882702212692308056024281175802607700426526000495235781464187268985316355546978912530579053491968145752746720495213034211965438416298865678974339803258684849814383125421063166939821410053665460303868944551299858094210708807124261007787849536528397806251
Related
I am trying to find the number of ways to construct an array such that consecutive positions contain different values.
Specifically, I need to construct an array with elements such that each element 1 between and k , all inclusive. I also want the first and last elements of the array to be 1 and x.
Complete problem statement:
Here is what I tried:
def countArray(n, k, x):
# Return the number of ways to fill in the array.
if x > k:
return 0
if x == 1:
return 0
def fact(n):
if n == 0:
return 1
fact_range = n+1
T = [1 for i in range(fact_range)]
for i in range(1,fact_range):
T[i] = i * T[i-1]
return T[fact_range-1]
ways = fact(k) / (fact(n-2)*fact(k-(n-2)))
return int(ways)
In short, I did K(C)N-2 to find the ways. How could I solve this?
It passes one of the base case with inputs as countArray(4,3,2) but fails for 16 other cases.
Let X(n) be the number of ways of constructing an array of length n, starting with 1 and ending in x (and not repeating any numbers). Let Y(n) be the number of ways of constructing an array of length n, starting with 1 and NOT ending in x (and not repeating any numbers).
Then there's these recurrence relations (for n>1)
X(n+1) = Y(n)
Y(n+1) = X(n)*(k-1) + Y(n)*(k-2)
In words: If you want an array of length n+1 ending in x, then you need an array of length n not ending in x. And if you want an array of length n+1 not ending in x, then you can either add any of the k-1 symbols to an array of length n ending in x, or you can take an array of length n not ending in x, and add any of the k-2 symbols that aren't x and don't repeat the last value.
For the base case, n=1, if x is 1 then X(1)=1, Y(1)=0 otherwise, X(1)=0, Y(1)=1
This gives you an O(n)-time method of computing the result.
def ways(n, k, x):
M = 10**9 + 7
wx = (x == 1)
wnx = (x != 1)
for _ in range(n-1):
wx, wnx = wnx, wx * (k-1) + wnx*(k-2)
wnx = wnx % M
return wx
print(ways(100, 5, 2))
In principle you can reduce this to O(log n) by expressing the recurrence relations as a matrix and computing the matrix power (mod M), but it's probably not necessary for the question.
[Additional working]
We have the recurrence relations:
X(n+1) = Y(n)
Y(n+1) = X(n)*(k-1) + Y(n)*(k-2)
Using the first, we can replace the Y(_) in the second with X(_+1) to reduce it down to a single variable. Then:
X(n+2) = X(n)*(k-1) + X(n+1)*(k-2)
Using standard techniques, we can solve this linear recurrence relation exactly.
In the case x!=1, we have:
X(n) = ((k-1)^(n-1) - (-1)^n) / k
And in the case x=1, we have:
X(n) = ((k-1)^(n-1) - (1-k)(-1)^n)/k
We can compute these mod M using Fermat's little theorem because M is prime. So 1/k = k^(M-2) mod M.
Thus we have (with a little bit of optimization) this short program that solves the problem and runs in O(log n) time:
def ways2(n, k, x):
S = -1 if n%2 else 1
return ((pow(k-1, n-1, M) + S) * pow(k, M-2, M) - S*(x==1)) % M
could you try this DP version: (it's passed all tests) (it's inspired by #PaulHankin and take DP approach - will run performance later to see what's diff for big matrix)
def countArray(n, k, x):
# Return the number of ways to fill in the array.
big_mod = 10 ** 9 + 7
dp = [[1], [1]]
if x == 1:
dp = [[1], [0]]
else:
dp = [[1], [1]]
for _ in range(n-2):
dp[0].append(dp[0][-1] * (k - 1) % big_mod)
dp[1].append((dp[0][-1] - dp[1][-1]) % big_mod)
return dp[1][-1]
I have a math function whose output is defined by two variables, x and y.
The function is e^(x^3 + y^2).
I want to calculate every possible integer combination between 1 and some defined integer for x and y, and place them in an array so that each output is aligned with the cooresponding x value and y value index. So something like:
given:
x = 3
y = 5
output would be an array like this:
f(1,1) f(1,2) f(1,3)
f(2,1) f(2,2) f(2,3)
f(3,1) f(3,2) f(3,3)
f(4,1) f(4,2) f(4,3)
f(5,1) f(5,2) f(5,3)
I feel like this is an easy problem to tackle but I have limited knowledge. The code that follows is the best description.
import math
import numpy as np
equation = math.exp(x**3 + y**2)
#start at 1, not zero
i = 1
j = 1
#i want an array output
output = []
#function
def shape_f (i,j):
shape = []
output.append(shape)
while i < x + 1:
while j < y +1:
return math.exp(i**3 + j**2)
#increase counter
i = i +1
j = j +1
print output
I've gotten a blank array recently but I have also gotten one value (int instead of an array)
I am not sure if you have an indentation error, but it looks like you never do anything with the output of the function shape_f. You should define your equation as a function, rather than expression assignment. Then you can make a function that populates a list of lists as you describes.
import math
def equation(x, y):
return math.exp(x**3 + y**2)
def make_matrix(x_max, y_max, x_min=1, y_min=1):
out = []
for i in range(x_min, x_max+1):
row = []
for j in range(y_min, y_max+1):
row.append(equation(i, j))
out.append(row)
return out
matrix = make_matrix(3, 3)
matrix
# returns:
[[7.38905609893065, 148.4131591025766, 22026.465794806718],
[8103.083927575384, 162754.79141900392, 24154952.7535753],
[1446257064291.475, 29048849665247.426, 4311231547115195.0]]
We can do this very simply with numpy.
First, we use np.arange to generate a range of values from 0 (to simplify indexing) to a maximum value for both x and y. We can perform exponentiation, in a vectorised manner, to get the values of x^3 and y^2.
Next, we can apply np.add on the outer product of x^3 and y^3 to get every possible combination thereof. The final step is taking the natural exponential of the result:
x_max = 3
y_max = 5
x = np.arange(x_max + 1) ** 3
y = np.arange(y_max + 1) ** 2
result = np.e ** np.add.outer(x, y)
print(result[2, 3]) # e^(2 ** 3 + 3 ** 2)
Output:
24154952.753575277
A trivial solution would be to use the broadcasting feature of numpy with the exp function:
x = 3
y = 5
i = np.arange(y).reshape(-1, 1) + 1
j = np.arange(x).reshape(1, -1) + 1
result = np.exp(j**3 + y**2)
The reshape operations make i into a column with y elements and j into a row with x elements. Exponentiation does not change those shapes. Broadcasting happens when you add the two arrays together. The unit dimensions in one array get expanded to the corresponding dimension in the other. The result is a y-by-x matrix.
I am trying to solve a set of linear simultaneous equations using linsolve in Sympy over a range of values. For simplicity I am showing below what I have been trying to do using simple equations.
from sympy import symbols, linsolve, IndexedBase
m = 2
n = symbols('n', integer=True)
x, y = symbols('x, y', cls=IndexedBase)
for n in range (0, m+1):
E1 = 2*x[n] + 5*y[n] - 33 + 2*n
E2 = x[n] + 3*y[n] - 19 + 4*n
sol = linsolve([E1, E2], [x[n], y[n]])
(x[n], y[n]) = tuple(*sol)
This returns an error "'IndexedBase' object does not support item assignment". How can I map the solution values to the indexed symbols so that I will be able to use them later in the code (e.g., take the sum of all x values (x[0] + x[1] + x[2])? I am looking for a robust solution as for the real equations the value of m can be around 500.
SymPy objects are immutable; one cannot attach numeric data to them. "x" is always just that, a symbol "x"; and "x[2]" is an indexed symbol "x[2]". They do not get associated with any numeric values. To store solutions, use a list of tuples or a dictionary (or list of dictionaries), whichever is more convenient.
solutions = {}
for n in range(0, m+1):
E1 = 2*x[n] + 5*y[n] - 33 + 2*n
E2 = x[n] + 3*y[n] - 19 + 4*n
sol = linsolve([E1, E2], [x[n], y[n]])
solutions.update(dict(zip([x[n], y[n]], *sol)))
print(solutions)
This prints {x[0]: 4, y[0]: 5, x[1]: 18, y[1]: -1, x[2]: 32, y[2]: -7}. You can then use this dictionary in subs:
expr = x[0] + 3*y[2]
print(expr.subs(solutions)) # -17
I am trying to solve a problem where I want to find the max product of any 3 integers in an array.
I tried my solution:
def maximumProduct(nums):
"""
:type nums: List[int]
:rtype: int
"""
list_of_ints = nums
t = sorted(list_of_ints[:4])
max_pos = t[2]
max_pos_2 = t[1]
max_pos_3 = t[0]
min_neg = 0
min_neg_2 = 0
for x in list_of_ints[3:]:
if x<0 and x< min_neg:
temp = min_neg
min_neg = x
min_neg_2 = temp
elif x<0 and x<min_neg_2:
min_neg_2 = x
if x>0 and x>max_pos:
temp = max_pos
max_pos = x
temp2 = max_pos_2
max_pos_2 = temp
max_pos_3 = temp2
elif x>0 and x>max_pos_2:
temp = max_pos_2
max_pos_2 = x
max_pos_3 = temp
elif x>0 and x>max_pos_3:
max_pos_3 = x
return max(max_pos*max_pos_2*max_pos_3, min_neg*min_neg_2*max_pos)
The above solution fails on input nums = [-1, -2, -3]. The expected output is -6, the output of the program is 0.
This is due to the initialization of min_neg and min_neg_1 to zero.
How to initialize to avoid this issue? I always have trouble setting up the right initializations.
Approach
To solve this kind of exercise efficiently, you need to recognize that there are only a few possible cases. Focus on the signs of the numbers and think what would be the sign of the result:
+ * + * + = + (good)
+ * + * - = - (bad)
+ * - * - = + (good)
- * - * - = - (bad)
anything * 0 = 0 (neutral)
So, if the list has both negative and negative numbers, the answer is either the product of the three largest numbers, or the product the two smallest (negative) numbers and the largest number (positive).
If this condition is not true, the answer must be the product of the largest numbers in the array.
O(n log (n)) solution
So, the answer has to take either the three last elements in the array after sorting, or the two first ones and the last one, and multiply them together. The simplest and most elegant way to do it is to first sort the list of numbers:
def maximum_product(nums): # O(n log(n)) solution
nums.sort()
assert len(nums) >= 3 # assume the input has been validated
a1 = nums[-1] * nums[-2] * nums[-3]
a2 = nums[0] * nums[1] * nums[-1]
return max(a1, a2)
O(n) solution
However, you can also find the maximal three and the minimal two numbers in O(n) time. One efficient approach how to find the maximum N numbers in a container is to keep a heap of size N while iterating through it. At the end, the heap contains the answer: a partially sorted list of N largest elements.
Python module heapq offers convenient API for this: the functions nlargest() and nsmallest(). So here we go:
import heapq
def maximum_product(nums): # O(n) solution
assert len(nums) >= 3 # assume the input has been validated
max3 = heapq.nlargest(3, nums)
min2 = heapq.nsmallest(2, nums)
a1 = max3[0] * max3[1] * max3[2]
a2 = min2[0] * min2[1] * max(max3)
return max(a1, a2)
You can initialize to negative infinity: min_neg = float('-inf')
You can use itertools.combinations to make doing it very easy. What you're calling an "array" is referred to as a "list" in Python, by-the-way.
from itertools import combinations
def maximum_product(nums):
return max(trio[0] * trio[1] * trio[2] for trio in combinations(nums, 3))
nums = [-1, -2, -3, 9]
print(maximum_product(nums)) # -> 54
This could be generalized to determine the maximum product of N integers by (also) using functools.reduce() to compute the product of N items:
from functools import reduce
from itertools import combinations
def maximum_product(nums, group_size):
return max(reduce(lambda a, b: a*b, nums, 1)
for group in combinations(nums, group_size))
nums = [-1, -2, -3, 9]
print(maximum_product(nums, 3)) # -> 54
Of course, this generality will slow execution down a bit...
Try this:
arr = sorted(list_of_ints)
def getMax(t):
maxP = t[0] * t[1] * t[2]
i = 0
while t[i] > -1:
i += 1
maxN = t[i] * t[i + 1] * t[0]
return max(maxP, maxN)
print(getMax(arr))
I tried kfx's O(n) solution but it was not taking into account possible negative ints for me. I added a few lines to adjust for that, and also two more possible combinations and it worked. Correct me if I am wrong but I think this is still O(n) notation right?
def maximum_product(nums):
max3 = heapq.nlargest(3, nums)
min3 = heapq.nsmallest(3, nums)
a1 = max3[0] * max3[1] * max3[2]
a2 = min3[0] * min3[1] * min3[2]
a3 = min3[0] * max3[0] * max3[1]
a4 = min3[0] * min3[1] * max3[0]
if abs(min(a1, a2, a3, a4)) > abs(max(a1, a2, a3, a4)):
return min(a1, a2, a3, a4)
else:
return max(a1, a2, a3, a4)
I have two quantities a & b that are defined by recursion and through reference to another list of values x = [ x_1, x_2, ... x_N ], which will be an input to the program. The program will iterate over all the values in x and update a & b according to:
for n in range(1,N)
a[n] = a[n-1] * exp(+x[n]) + b[n-1] * exp(-x[n])
b[n] = b[n-1] * exp(+x[n]) + a[n-1] * exp(-x[n])
and starting values
a[0] = exp(+x[0])
b[0] = exp(-x[0])
The values in x are not big numbers (always <10) but N will be in the hundreds, and because of all the exponentials the final values of a & b will be very large. I'm worried that because of the form of the recursion where we are constantly multiplying exponentially large numbers with exponentially small ones and adding them this scheme will become quite numerically unstable.
Ideally I would calculate log(a) and log(b) instead to stop the values becoming too large. But because of the recursion scheme that's not possible, unless I compute something much messier like
log_a[n] = x[n] + log_a[n-1] + log( 1 + exp(-2*x[n] + log_b[n-1]-log_a[n-1] ) )
Is numerical stability something I am right to be concerned about here? And if so would something like the log based scheme help to stabilise it?
We can rewrite that first as:
for n in range(1,N)
a[n] = exp(log(a[n-1]) + x[n]) + exp(log(b[n-1]) - x[n])
b[n] = exp(log(b[n-1]) + x[n]) + exp(log(a[n-1]) - x[n]))
Then change our iteration variables:
for n in range(1,N)
log_a[n] = log(exp(log_a[n-1] + x[n]) + exp(log_b[n-1] - x[n]))
log_b[n] = log(exp(log_b[n-1] + x[n]) + exp(log_a[n-1] - x[n]))
Which can be computed more stably using np.logaddexp:
for n in range(1,N)
log_a[n] = np.logaddexp(log_a[n-1] + x[n], log_b[n-1] - x[n])
log_b[n] = np.logaddexp(log_b[n-1] + x[n], log_a[n-1] - x[n])
The implementation of logaddexp can be seen here
As far as I'm aware, all(?) recursive problems can be solved through dynamic programming. For example, the Fibonacci sequence could be expressed like so:
def fibo(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibo(n-1) + fibo(n-2)
Or, iteratively:
n = 10
fibo_nums = [0, 1]
while len(fibo_nums) <= n:
fibo_nums.append(fibo_nums[-2] + fibo_nums[-1])
Presumably if you have a recursive problem you could perform a similar unpacking.