Value for each row in Pascal Triangle - Recursion - python

In the following code:
def pascal_row(row):
if row == 0:
return [1]
previous_row = pascal_row(row - 1)
pairs = zip(previous_row[:-1], previous_row[1:])
return [1] + map(sum, pairs) + [1]
if I print (pascal_row(5)), it returns [1, 5, 10, 10, 5, 1] which is the correct solution.
This is a homework assignment where we need to use recursion, and cannot use any loops or zip.
Could someone please help me convert it accordingly? Thank you!

You can use a different recursive function sliding_sum in order to calculate the pairwise sum for the previous row. Then, just append [1] on either end.
def sliding_sum(someList):
if len(someList) == 1:
return []
return [someList[0] + someList[1]] + sliding_sum(someList[1:])
def pascal_row(row):
if row == 0:
return [1]
previous_row = pascal_row(row-1)
new_row = [1] + sliding_sum(previous_row) + [1]
return new_row
for i in range(6):
print pascal_row(i)
Output
[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]

Here's another solution involving a helper function:
def pascal_row(row):
if row == 0:
return [1]
return _pascal_row(row, 0, [1])
def _pascal_row(target_row, current_row, res):
if target_row == current_row:
return res
else:
res = [1] + [res[i] + res[i+1] for i in xrange(len(res) - 1)] + [1]
return _pascal_row(target_row, current_row + 1, res)
print pascal_row(5) # [1, 5, 10, 10, 5, 1]

Related

Python for each element in a list add the value of previous index and next index

For each element in a list I want to add the value before and after the element and append the result to an empty list. The problem is that at index 0 there is no index before and at the end there is no index next. At index 0 I want to add the value of index 0 with value of index 1, and in the last index I want to add the value of the last index with the same index value. As following:
vec = [1,2,3,4,5]
newVec = []
for i in range(len(vec)):
newValue = vec[i] + vec[i+1] + vec[i-1]
# if i + 1 or i - 1 does now exist pass
newVec.append(newValue)
Expected output: newVec = [1+2, 2+1+3, 3+2+4,4+3+5,5+4]
# newVec = [3, 6, 9, 12, 9]
You have possible exceptions here, I think this code will do the trick and manage the exceptions.
vec = [1, 2, 3, 4, 5]
new_vec = []
for index, number in enumerate(vec):
new_value = number
if index != 0:
new_value += vec[index - 1]
try:
new_value += vec[index + 1]
except IndexError:
pass
new_vec.append(new_value)
Your output will look like this:
[3, 6, 9, 12, 9]
Good luck !
You can make the conditions inside the for loop
for i in range(len(vec)):
if i == 0 :
newValue = vec[i] + vec[i+1]
elif i == len(vec)-1:
newValue = vec[i] + vec[i-1]
else:
newValue = vec[i] + vec[i+1] + vec[i-1]
newVec.append(newValue)
print(newVec)
output:
[3, 6, 9, 12, 9]
You can just add 0 to either side of vec so that it's adding nothing to create an accurate result. Then just use a for i in range(1, ...) loop, starting at value 1 to add value before and after i. This is what i got for my code:
vec = [1,2,3,4,5]
newVec = []
vec.insert(0, 0)
vec.insert(len(vec) + 1, 0)
for i in range(1, len(vec) - 1):
newVec.append(vec[i-1] + vec[i] + vec[i+1])
print(newVec)
Which creates the output of:
[3, 6, 9, 12, 9]
Hope this helps.

could someone explain in detail on this ((sum(x[i-n:i+n+1]))..where does i-n:i+n+1 start and end?

could someone explain in detail on this ((sum(x[i-n:i+n+1]))..where does i-n:i+n+1 start and end??
i just don't want to copy the code`
The function should create a return a new list r where
def smooth_a(x, n):
x = [x[0]]*n+x+[x[-1]]*n #creates a copy of x
res = [] #empty list
for i in range(n, len(x)-n):
res.append(sum(x[i-n:i+n+1])/(2*n+1))
return res
x = [1, 2, 6, 4, 5, 0, 1, 2] #def of x
print('smooth_a(x, 1): ', smooth_a(x, 1)) #prints new list with n=1
Let's say x = [1, 2, 6, 4, 5, 0, 1, 2] and n = 1
Then, if you take i = 3 for example:
sum(x[i-n:i+n+1]) = sum(x[2:5])
= sum([6, 4, 5]) <- slices x from 2 to 4, both inclusive
= 15
For your specific problem, be careful with the lower slice index, if it's negative, the slicing will return an empty list, so I would write it as sum(x[max(i-n, 0):i+n+1]).

How can I store the elements(indexes) that produced the maximum sum where non-adjacent numbers were picked in a given array (Dynamic programming)

I'm new to dynamic programming in python and this is the code I have done so far to get the numbers that give the max sum from the array. However, my code doesn't work for input array A
Here are cases:
Test cases:
A = [7,2,-3,5,-4,8,6,3,1]
B = [7,2,5,8,6]
C = [-2,3,1,10,3,-7]
Output:
A = [7,5,8,3]
B = [7,5,6]
C = [3,10]
My output works for B and C but not for array A. The output I get is this:
[7,6,1]
And Here is my code:
def max_sum(nums):
#Get the size of the array
size = len(nums)
list = []
cache = [[0 for i in range(3)] for j in range(size)]
if(size == 0):
return 0
if (size == 1):
return nums[0]
for i in range(0, size):
if(nums[i] < 0):
validate = i
if(size == validate + 1):
return []
#Create array 'cache' to store non-consecutive maximum values
#cache = [0]*(size + 1)
#base case
cache[0][2] = nums[0]
#temp = nums[0]
cache[0][1] = nums[0]
for i in range(1, size):
#temp1 = temp
cache[i][2] = nums[i] #I store the array numbers at index [I][2]
cache[i][1] = cache[i - 1][0] + nums[I] #the max sum is store here
cache[i][0] = max(cache[i - 1][1], cache[i -1][0]) #current sum is store there
maxset = 0
for i in range(0, size): #I get the max sum
if(cache[i][1] > maxset):
maxset = cache[i][1]
for i in range(0, size): #I get the first element here
if(cache[i][1] == maxset):
temp = cache[i][2]
count = 0
for i in range(0, size): # I check at what index in the nums array the index 'temp' is store
if(nums[i] != temp):
count += 1
if(size - 1 == count): #iterate through the nums array to apend the non-adjacent elements
if(count % 2 == 0):
for i in range(0, size):
if i % 2 == 0 and i < size:
list.append(nums[i])
else:
for i in range(0, size):
if i % 2 != 0 and i < size:
list.append(nums[i])
list[:]= [item for item in list if item >= 0]
return list
if __name__ == '__main__':
A = [7,2,-3,5,-4,8,6,3,1]
B = [7,2,5,8,6]
C = [-2,3,1,10,3,-7]
'''
Also, I came up with the idea to create another array to store the elements that added to the max sum, but I don't know how to do that.
Any guidance would be appreciated and thanks beforehand!
Probably not the best solution , but what about trying with recursion ?
tests = [([7, 2, -3, 5, -4, 8, 6, 3, 1], [7, 5, 8, 3]),
([7, 2, 5, 8, 6], [7, 5, 6]),
([-2, 3, 1, 10, 3, -7], [3, 10]),
([7, 2, 9, 10, 1], [7, 9, 1]),
([7, 2, 5, 18, 6], [7, 18]),
([7, 20, -3, -5, -4, 8, 60, 3, 1], [20, 60, 1]),
([-7, -20, -3, 5, -4, 8, 60, 3, 1], [5, 60, 1])]
def bigest(arr, cache, final=[0]):
if len(arr) == 0:
return cache
for i in range(len(arr)):
result = bigest(arr[i + 2:], [*cache, arr[i]], final)
if sum(cache) > sum(final):
final[:] = cache[:]
if sum(result) > sum(final):
final[:] = result[:]
return result
if __name__ == "__main__":
print("has started")
for test, answer in tests:
final = [0]
bigest(test, [], final)
assert final == answer, "not matching"
print(f"for {test} , answer: {final} ")
Here is a dynamic programming approach.
def best_skips (data):
answers = []
for i in range(len(data)):
x = data[i]
best = [0, None]
for prev in answers[0:i-1]:
if best[0] < prev[0]:
best = prev
max_sum, path = best
answers.append([max_sum + x, [x, path]])
answers.append([0, None]) # Add empty set as an answer.
path = max(answers)[1]
final = []
while path is not None:
final.append(path[0])
path = path[1]
return final

Why my array didn't change original value after a function

def prefix_sum_inplace0(arr_in):
n = len(arr_in)
arr_in = [0] + arr_in
arr_in.pop()
for i in range (1, n):
arr_in[i] = arr_in[i - 1] + arr_in[i]
return arr_in
arr1 = [5, 4, 3, 2, 4, 7, 6, 11]
print("pre_sum_inplace0:",prefix_sum_inplace0(arr1),"original arr:",arr1)
explaining: I want to calculate the exclusive prefix sum of array,
for example if original array is [1,2,3,4], so the exclusive sum of array is [0,1,3,6],
I don't know why the original array didn't change because this function didn't return a new array
A new list is created when you do arr_in = [0] + arr_in. I added a few print commands so you can see the list's id change. arr_in isn't modified before the addition of [0] at the beginning, so arr1 stays the same.
def prefix_sum_inplace0(arr_in):
print(id(arr_in))
n = len(arr_in)
arr_in = [0] + arr_in
print(id(arr_in))
arr_in.pop()
for i in range (1, n):
arr_in[i] = arr_in[i - 1] + arr_in[i]
return arr_in
arr1 = [5, 4, 3, 2, 4, 7, 6, 11]
print(id(arr1))
print("pre_sum_inplace0:",prefix_sum_inplace0(arr1),"original arr:",arr1)
I change some method about adding and deleting elements and it did work.
def prefix_sum_inplace0(arr_in):
arr_in.insert(0, 0)
del arr_in[-1]
n = len(arr_in)
for i in range (1, n):
arr_in[i] = arr_in[i - 1] + arr_in[i]
return arr_in
This will work, When you performed "arr_in = [0] + arr_in" it performed an initialization. You can see by using "hex(id(arr_in))" the address of the list changed. Use insert(0,0) instead. It'll not change the address of the list means initialization not performed.
def prefix_sum_inplace0(arr_in):
n = len(arr_in)
arr_in.insert(0,0)
arr_in.pop()
for i in range (1, n):
arr_in[i] = arr_in[i - 1] + arr_in[i]
return arr_in
arr1 = [5, 4, 3, 2, 4, 7, 6, 11]
print("pre_sum_inplace0:",prefix_sum_inplace0(arr1),"original arr:",arr1)

counting up and then down a range in python

I am trying to program a standard snake draft, where team A pick, team B, team C, team C, team B, team A, ad nauseum.
If pick number 13 (or pick number x) just happened how can I figure which team picks next for n number of teams.
I have something like:
def slot(n,x):
direction = 'down' if (int(x/n) & 1) else 'up'
spot = (x % n) + 1
slot = spot if direction == 'up' else ((n+1) - spot)
return slot
I have feeling there is a simpler, more pythonic what than this solution. Anyone care to take a hack at it?
So I played around a little more. I am looking for the return of a single value, rather than the best way to count over a looped list. The most literal answer might be:
def slot(n, x): # 0.15757 sec for 100,000x
number_range = range(1, n+1) + range(n,0, -1)
index = x % (n*2)
return number_range[index]
This creates a list [1,2,3,4,4,3,2,1], figures out the index (e.g. 13 % (4*2) = 5), and then returns the index value from the list (e.g. 4). The longer the list, the slower the function.
We can use some logic to cut the list making in half. If we are counting up (i.e. (int(x/n) & 1) returns False), we get the obvious index value (x % n), else we subtract that value from n+1:
def slot(n, x): # 0.11982 sec for 100,000x
number_range = range(1, n+1) + range(n,0, -1)
index = ((n-1) - (x % n)) if (int(x/n) & 1) else (x % n)
return number_range[index]
Still avoiding a list altogether is fastest:
def slot(n, x): # 0.07275 sec for 100,000x
spot = (x % n) + 1
slot = ((n+1) - spot) if (int(x/n) & 1) else spot
return slot
And if I hold the list as variable rather than spawning one:
number_list = [1,2,3,4,5,6,7,8,9,10,11,12,12,11,10,9,8,7,6,5,4,3,2,1]
def slot(n, x): # 0.03638 sec for 100,000x
return number_list[x % (n*2)]
Why not use itertools cycle function:
from itertools import cycle
li = range(1, n+1) + range(n, 0, -1) # e.g. [1, 2, 3, 4, 4, 3, 2, 1]
it = cycle(li)
[next(it) for _ in xrange(10)] # [1, 2, 3, 4, 4, 3, 2, 1, 1, 2]
Note: previously I had answered how to run up and down, as follows:
it = cycle(range(1, n+1) + range(n, 0, -1)) #e.g. [1, 2, 3, 4, 3, 2, 1, 2, 3, ...]
Here's a generator that will fulfill what you want.
def draft(n):
while True:
for i in xrange(1,n+1):
yield i
for i in xrange(n,0,-1):
yield i
>>> d = draft(3)
>>> [d.next() for _ in xrange(12)]
[1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1]
from itertools import chain, cycle
def cycle_up_and_down(first, last):
up = xrange(first, last+1, 1)
down = xrange(last, first-1, -1)
return cycle(chain(up, down))
turns = cycle_up_and_down(1, 4)
print [next(turns) for n in xrange(10)] # [1, 2, 3, 4, 4, 3, 2, 1, 1, 2]
Here is a list of numbers that counts up, then down:
>>> [ -abs(5-i)+5 for i in range(0,10) ]
[0, 1, 2, 3, 4, 5, 4, 3, 2, 1]
Written out:
count_up_to = 5
for i in range( 0, count_up_to*2 ):
the_number_you_care_about = -abs(count_up_to-i) + count_up_to
# do stuff with the_number_you_care_about
Easier to read:
>>> list( range(0,5) ) + list( range( 5, 0, -1 ) )
[0, 1, 2, 3, 4, 5, 4, 3, 2, 1]
Written out:
count_up_to = 5
for i in list( range(0,5) ) + list( range(5, 0, -1) ):
# i is the number you care about
Another way:
from itertools import chain
for i in chain( range(0,5), range(5,0,-1) ):
# i is the number you care about

Categories