1

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. enter image description here

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. enter image description here

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.

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

2 Comments

Much appreciated @petercd! Thank you!
@blowtorch: were you able to recover the solution from the above memoized table?
0

A little late to the party but I am currently doing an Algorithms course and part of the assignment is this exact question. Here's my implementation:

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
    # your code here
    if i == len(a):
        return 0
    if i < len(a):
        if aj is not None and abs(a[i] - aj) > 1:
            return lssLength(a, i+1, j)
        elif aj is None or abs(a[i] - aj) <= 1:
            return max(lssLength(a, i+1, i) + 1, lssLength(a, i+1, j))

When memoizing it, I basically used the same recurrence structure but the task was to figure out the loops:

def memoizeLSS(a):
    T = {} # Initialize the memo table to empty dictionary
    # 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 
    # 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)]
    # your code here
    for i in range(n-1, -1, -1): # so that i+1 would be from n to 0
        for j in range(-1, i): # because 0 <= i <= n and -1 <= j < i
            aj = a[j] if 0 <= j < len(a) else None
            if aj is not None and abs(a[i] - aj) > 1:
                T[(i,j)] = T[(i+1, j)]
            elif aj is None or abs(a[i] - aj) <= 1:
                T[(i,j)] = max(T[(i+1, i)] + 1, T[(i+1, j)])
    return T

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.