pythonpython-3.xreadabilitylis

I can't understand fully this line of code


I was solving a problem on LIS (Longest Increasing Subset) and I couldn't solve it completely. I googled for some solutions and on rosettacode I found several ones. I liked this one because it looks very short and straight forward (so easier to understand). But it's written in such a way that I am having serious troubles rewriting it.

for i in range(len(d)):
        l.append(max([l[j] for j in range(i)
                     if l[j][-1] < d[i]] 
                         or [[]], key=len) 
                   + [d[i]]
                )

This is the part I am having troubles to understand. This is what I think I understood:

append to the solutions array the longest combination of numbers in the solutions array, lower than the current number i am considering from the input array; plus the number you are considering from the input array. (Sorry for my English).

I feel like I didn't understand fully what the code is doing.

def longest_increasing_subsequence(d):
    'Return one of the L.I.S. of list d'
    l = []
    for i in range(len(d)):
        l.append(max([l[j] for j in range(i) if l[j][-1] < d[i]] or [[]], key=len) 
                  + [d[i]])
    return max(l, key=len)

if __name__ == '__main__':
    for d in [[3,2,6,4,5,1], [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]]:
        print('a L.I.S. of %s is %s' % (d, longest_increasing_subsequence(d)))

Solution

  • Let me expand out the code for you:

    def longest_increasing_subsequence(d):
        'Return one of the L.I.S. of list d'
        l = []
        for i in range(len(d)):
            # currently the LIS is just this number
            lis_at_this_index = [d[i]]
            # for all the previous LIS
            for j in range(i):
                # if d[i] can be added to it and still be increasing
                if l[j][-1] < d[i]:
    
                    # update the candidate LIS at this index
                    lis_at_this_index = max(lis_at_this_index, l[j] + [d[i]], key=len)
            l.append(lis_at_this_index)
        # return the global maximum
        return max(l, key=len)
    

    The idea is that if we have the LIS for indices [0..i-1], we can compute the LIS for index i like so:

    1. For each LIS [0...i-1], check if adding d[i] is allowed
    2. If it is allowed that is a candidate LIS for index i
    3. The longest out of all the candidates is the LIS at index i

    And then you return the longest out of all the LIS at each index.