Dynamic Programming, create a memo table longest stable subsequence - python-3.x

I have worked on a dynamic programming problem for quite some time now and am stuck, so any help is much appreciated.
Here is the first part of the problem which I was able to get the tests to pass.
def lssLength(a, i, j):
aj = a[j] if 0 <= j < len(a) else None
# Implement the recurrence below. Use recursive calls back to lssLength
assert 0 <= i <= len(a)
if i >= len(a) or j >= len(a):
return 0
if aj and abs(a[i] - a[j]) > 1:
return lssLength(a, i+1, j)
if aj is None or (abs(a[i] - a[j]) <= 1 and i != j):
return max(lssLength(a, i+1, j), lssLength(a, i+1, i) + 1)
else:
return lssLength(a, i+1, j)
Here are my test cases for the first problem:
def test_lss_length(self):
# test 1
n1 = lssLength([1, 4, 2, -2, 0, -1, 2, 3], 0, -1)
print(n1)
self.assertEqual(4, n1)
# test 2
n2 = lssLength([1, 2, 3, 4, 0, 1, -1, -2, -3, -4, 5, -5, -6], 0, -1)
print(n2)
self.assertEqual(8, n2)
# test 3
n3 = lssLength([0, 2, 4, 6, 8, 10, 12], 0, -1)
print(n3)
self.assertEqual(1, n3)
# test 4
n4 = lssLength(
[4, 8, 7, 5, 3, 2, 5, 6, 7, 1, 3, -1, 0, -2, -3, 0, 1, 2, 1, 3, 1, 0, -1, 2, 4, 5, 0, 2, -3, -9, -4, -2, -3,
-1], 0, -1)
print(n4)
self.assertEqual(14, n4)
Now I need to take the recursive solution and convert it to dynamic programming, and this is where I am stuck. I am using the same tests as before, but the tests are failing.
def memoizeLSS(a):
T = {} # Initialize the memo table to empty dictionary
# Now populate the entries for the base case
# Now fill out the table : figure out the two nested for loops
# It is important to also figure out the order in which you iterate the indices i and j
# Use the recurrence structure itself as a guide: see for instance that T[(i,j)] will depend on T[(i+1, j)]
n = len(a)
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
if abs(a[i] - a[j]) > 1:
try:
T[(i, j)] = max(0, T[(i, j+1)], T[(i+1, j)])
except Exception:
T[(i, j)] = 0
elif abs(a[i] - a[j]) <= 1 and i != j:
T[(i, j)] = T[(i+1, j+1)] + 1
else:
T[(i, j)] = max(0, T[(i+1, j+1)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T
If you've read all of this, thank you so much. I know it is a lot and really appreciate your time. Any pointers to reading materials, etc. is much appreciated.
If there are more details required, please let me know. Thanks.

Your solution only worked for the first test case. Below is a corrected version:
def memoizeLSS(a):
T = {} # Initialize the memo table to empty dictionary
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
# Now populate the entries for the base case
# Now fill out the table : figure out the two nested for loops
# It is important to also figure out the order in which you iterate the indices i and j
# Use the recurrence structure itself as a guide: see for instance that T[(i,j)] will depend on T[(i+1, j)]
n = len(a)
for i in range(0, n + 1):
for j in range(-1, n + 1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i+1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i+1, i)] + 1, T[(i + 1, j)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T

Related

Recover solution from dynamic programming memo table

My goal is to find the longest sub-list of a list of numbers such that each element is at most 1 away from each other, e.g., a list of [0,1,2,2,3,3] from the list [0,4,1,2,2,3,3,1]. I create the memo table as follows:
def memoizeLSS(a):
T = {}
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i + 1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i + 1, i)] + 1, T[(i + 1, j)])
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
return T
I can figure out the maximum length, however I'm having trouble reconstructing the subsequence from the memo table. I tried creating a list of paired indices where the numbers are <= 1 away from and building it up from there, but there are pairs of indices which are not part of the sub-sequence and I'm stumped on what to do from here or even if creating this list is useful:
def computeLSS(a):
T = {}
Y_list = []
# Now populate the entries for the base case
n = len(a)
for j in range(-1, n):
T[(n, j)] = 0 # i = n and j
for i in range(0, n+1):
for j in range(-1, n+1):
T[(i, j)] = 0
for i in range(n-1, -1, -1):
for j in range(n-1, -1, -1):
aj = a[j] if 0 <= j < len(a) else None
if aj != None and abs(a[i] - a[j]) > 1:
T[(i, j)] = T[(i + 1, j)]
elif aj == None or abs(a[i] - a[j]) <= 1:
T[(i, j)] = max(T[(i + 1, i)] + 1, T[(i + 1, j)])
if T[(i, j)] == T[(i + 1, i)] + 1 and a[i] != a[j]:
Y_list.append((i, j))
for i in range(n-2, -1, -1):
T[(i, -1)] = max(T[(i+1, -1)], T[(i+1, 0)], T[(i, 0)], 0)
Y_list_new = []
for x,y in Y_list:
if x==y:
pass
if (y,x) in Y_list_new:
pass
else:
Y_list_new.append((x,y))
print(Y_list_new)
#print(T)
return
Any help is appreciated. Thank you!

Can someone help me to figure out what's wrong in my implementation of merge sort?

My implementation:
def merge_sort(arr):
if len(arr) <= 1:
return arr
left = arr[:len(arr)//2]
right = arr[len(arr)//2:]
merge_sort(left)
merge_sort(right)
return merge(left, right)
def merge(left, right):
leftI = rightI = 0
merged = []
while (leftI < len(left) and rightI < len(right)):
if left[leftI] < right[rightI]:
merged.append(left[leftI])
leftI += 1
else:
merged.append(right[rightI])
rightI += 1
merged.extend(left[leftI:])
merged.extend(right[rightI:])
return merged
if __name__ == '__main__':
arr = [1,2,5,5,9,22,6,3,6,8,1,43,5]
print(merge_sort(arr))
For some reason I am obtaining:
[1, 2, 5, 5, 6, 3, 6, 8, 1, 9, 22, 43, 5]
Working Implementation (Got from a friend):
def merge_sort(list):
list_length = len(list)
if list_length == 1:
return list
mid_point = list_length // 2
left_partition = merge_sort(list[:mid_point])
right_partition = merge_sort(list[mid_point:])
return merge(left_partition, right_partition)
def merge(left, right):
output = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
output.append(left[i])
i += 1
else:
output.append(right[j])
j += 1
output.extend(left[i:])
output.extend(right[j:])
return output
if __name__ == '__main__':
arr = [1,2,5,5,9,22,6,3,6,8,1,43,5]
print(merge_sort(arr))
This code yeilds:
[1, 1, 2, 3, 5, 5, 5, 6, 6, 8, 9, 22, 43]
I just can't figure out what's wrong. It'd be a great help if someone could take a few moments to help me out :)
In your merge_sort function, you do not change the values of left and right depending on what merge_sort returns.
You have :
merge_sort(left)
merge_sort(right)
Where it should be :
left = merge_sort(left)
right = merge_sort(right)

What is wrong with the syntax for this insertion sort and bubble sort code?

I am currently taking discrete structures and algorithms and have to work with python for the first time.
I am having a little trouble with the syntax and having a problem with my bubble sort and insertion sort function printing
def insertion_sort(numbers):
numbers = [1, 5, 9, 3, 4, 6]
for index in range(1, len(numbers)):
value = numbers[index]
i = index - 1
while i >= 0:
if value < numbers[i]:
numbers[i+1] = numbers[i]
numbers[i] = value
i = i - 1
print(numbers)
else:
break
def bubble_sort(numbers):
for i in range(0, len(numbers) - 1, 1):
for j in range(0, len(numbers) - 1 - i, 1):
if numbers[j] < numbers[j + 1]:
temp = numbers[j]
numbers[j] = numbers[j + 1]
numbers[j + 1] = temp
numbers = [1, 5, 9, 3, 4, 6]
print(numbers)
You've defined two functions but never call them. Therefore, they are not getting executed.
You've defined your two functions such that they expect a numbers parameter. So you need to call them with a list of numbers as input. eg. insertion_sort([1, 5, 9, 3, 4, 6])
Your functions are not returning any value. So they are simply taking the numbers list parameter, and sorting it. In order to access the result from outside the function, you need to add return numbers at the end of each function.
All in all, your code should look something like this:
def insertion_sort(numbers):
for index in range(1, len(numbers)):
value = numbers[index]
i = index - 1
while i >= 0:
if value < numbers[i]:
numbers[i+1] = numbers[i]
numbers[i] = value
i = i - 1
else:
break
return numbers
def bubble_sort(numbers):
for i in range(0, len(numbers) - 1, 1):
for j in range(0, len(numbers) - 1 - i, 1):
if numbers[j] < numbers[j + 1]:
temp = numbers[j]
numbers[j] = numbers[j + 1]
numbers[j + 1] = temp
return numbers
numberstosort = [1, 5, 9, 3, 4, 6]
print(insertion_sort(numberstosort))
print(bubble_sort(numberstosort))
This will print the output of each function. Output:
[1, 3, 4, 5, 6, 9]
[9, 6, 5, 4, 3, 1]

calculate the sum of the intervals based on the binary array

I have two matrix:
Binary A = [[1, 0, 1, 0], [0, 0, 1, 0]];
Matrix of values B = [[100, 200, 300, 400], [400, 300, 100, 200]];
I want to calculate the sum of the intervals that are formed by the rows of the matrix A. For my exmpl. result will be follow: R = [[300, 0, 700, 0], [0, 0, 300, 0]] (generally, it is not necessary to set zeros [[300, 700], [300]] - it's right solution too)
I already wrote the code, but very very terrible (although it works correctly)
def find_halfsum(row1, row2):
i = 0
result = []
count = 0
for j in range(len(row1)):
if row1[j] == 1 and count == 0:
i = j
count += 1
elif row1[j] == 1:
count += 1
if count == 2:
if j == i + 1:
result.append(row2[i])
else:
result.append(sum(row2[i:j]))
i = j
count = 1
if j == len(row1) - 1:
result.append(sum(row2[i:j + 1]))
return result
Someone knows beautiful solutions (which will be faster)(preferably with the help of a numpy)?
Thanks
Not familiar with python, but I don't think you need that many lines
define halfSum(matrixA, matrixB):
sum = 0;
for i in range(len(matrixA)):
if matrixA[i] == 1:
sum += matrixB[i]
return sum;
You can use numpy.add.reduceat:
>>> A = np.array([[1, 0, 1, 0], [0, 0, 1, 0]])
>>> B = np.array([[100, 200, 300, 400], [400, 300, 100, 200]])
>>>
>>> [np.add.reduceat(b, np.flatnonzero(a)) for a, b in zip(A, B)]
[array([300, 700]), array([300])]

Dynamic Programming: Tabulation of a Recursive Relation

The following recursive relation solves a variation of the coin exchange problem. Count the number of ways in which we can sum to a required value, while keeping the number of summands even:
def count_even(coins, num_coins, req_sum, parity):
if req_sum < 0:
return 0
if req_sum == 0 and not parity:
return 1
if req_sum == 0 and parity:
return 0
if num_coins == 0:
return 0
count_wout_high_coin = count_even(coins, num_coins - 1, req_sum, parity)
count_with_high_coin = count_even(coins, num_coins, req_sum - coins[num_coins - 1], not parity)
return count_wout_high_coin + count_with_high_coin
This code would yield the required solution if called with parity = False.
I am having issues implementing a tabulation technique to optimize this algorithm. On a first attempt I tried to follow the same pattern as for other DP problems, and took the parity as another parameter to the problem, so I coded this triple loop:
def count_even_tabulation(S, m, n):
if m <= 0 or n < 0:
return 0
if n == 0:
return 1
table = [[[0 for x in range(m)] for x in range(n + 1)] for x in range(2)]
for j in range(m):
table[0][0][j] = 1
table[1][0][j] = 0
for p in range(2):
for i in range(1, n + 1):
for j in range(m):
y = table[p][i][j - 1] if j >= 1 else 0
x = table[1 - p][i - S[j]][j] if i - S[j] >= 0 else 0
table[p][i][j] = x + y
return table[0][n][m - 1]
However, this approach is not creating the right tables for parity equal to 0 and equal to 1:
[1, 1, 1]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]
[1, 1, 1]
[0, 1, 1]
[0, 0, 1]
[0, 0, 0]
How can I adequately implement a tabulation approach for the given recursion relation?

Resources