Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this Longest Common Subsequence Correct?

I just wrote this implementation to find out the length of the longest increasing subsequence using dynamic programming. So for input as [10, 22, 9, 33, 21, 50, 41, 60, 80] the LIS is 6 and one of the set is [10, 22, 33, 50, 60, 80].

When I run the below code I get the correct answer as 6 with O(n) complexity. Is it correct?

def lis(a):
    dp_lis     = []
    curr_index = 0
    prev_index = 0

    for i in range(len(a)):
        prev_index = curr_index
        curr_index = i

        print 'if: %d < %d and %d < %d' % (prev_index, curr_index, a[prev_index], a[curr_index])
        if prev_index < curr_index and a[prev_index] < a[curr_index]:
            print '\tadd ELEMENT: ', a[curr_index]
            new_lis = 1 + max(dp_lis)
            dp_lis.append(new_lis)
        else:
            print '\telse ELEMENT: ', a[curr_index]
            dp_lis.append(1)

    print "DP LIST: ", dp_lis
    return max(dp_lis)

if __name__ == '__main__':
    a = [10, 22, 9, 33, 21, 50, 41, 60, 80]
    print lis(a)
like image 527
Srikar Appalaraju Avatar asked Feb 23 '26 03:02

Srikar Appalaraju


1 Answers

Use this correct, proven but inefficient implementation of the algorithm to check against your results - it's the standard recursive solution, it doesn't use dynamic programming:

def lis(nums):
    def max_length(i):
        if i == -1:
            return 0
        maxLen, curLen = 0, 0
        for j in xrange(i-1, -1, -1):
            if nums[j] < nums[i]:
                curLen = max_length(j)
                if curLen > maxLen:
                    maxLen = curLen
        return 1 + maxLen
    if not nums:
        return 0
    return max(max_length(x) for x in xrange(len(nums)))

Check to see if your_lis(nums) == my_lis(nums) for as many different-sized input lists with numbers as possible, they should be equal. At some point, for long lists my implementation will be far slower than yours.

As a further comparison point, here's my own optimized dynamic programming solution. It runs in O(n log k) time and O(n) space, returning the actual longest increasing subsequences it finds along the way:

def an_lis(nums):
    table, lis = lis_table(nums), []
    for i in xrange(len(table)):
        lis.append(nums[table[i]])
    return lis

def lis_table(nums):
    if not nums:
        return []
    table, preds = [0], [0] * len(nums)
    for i in xrange(1, len(nums)):
        if nums[table[-1]] < nums[i]:
            preds[i] = table[-1]
            table.append(i)
            continue
        minIdx, maxIdx = 0, len(table)-1
        while minIdx < maxIdx:
            mid = (minIdx + maxIdx) / 2
            if nums[table[mid]] < nums[i]:
                minIdx = mid + 1
            else:
                maxIdx = mid
        if nums[i] < nums[table[minIdx]]:
            if minIdx > 0:
                preds[i] = table[minIdx-1]
            table[minIdx] = i
    current, i = table[-1], len(table)
    while i:
        i -= 1
        table[i], current = current, preds[current]
    return table
like image 166
Óscar López Avatar answered Feb 25 '26 16:02

Óscar López



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!