300.Longest Increasing Subsequence

Tags: [dp], [inner_loop_dp]

Link: https://leetcode.com/problems/longest-increasing-subsequence/#/description

Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given[10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is[2, 3, 7, 101], therefore the length is4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n2) complexity.

Follow up:Could you improve it to O(nlogn) time complexity?


Solution: Inner Loop DP

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        # DP formula:
        # f[i] = max(f[j] + 1), 0<= j < i, nums[j] < nums[i].
        dp = [1 for _ in xrange(len(nums))]
        for i in xrange(1, len(nums)):
            for j in xrange(i):
                if nums[j] < nums[i]:
                    dp[i] = max(dp[i], dp[j] + 1)

        return max(dp)

Revelation:

  • See the comments in code.

Note:

  • Time complexity = O(n^2), n is the number of elements of the given nums.

Follow Up:

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0

        increasing_subseq = []
        for n in nums:
            if not increasing_subseq or n > increasing_subseq[-1]:
                increasing_subseq.append(n)
            else:
                # try to find the index i at where increasing_subseq[i - 1] <= n <= increasing_subseq[i]
                index = self.binary_search(increasing_subseq, n)
                increasing_subseq[index] = n

        return len(increasing_subseq)

    def binary_search(self, arr, target):
        # find the index i at where arr[i - 1] <= target <= arr[i]
        start = 0
        end = len(arr) - 1

        while start <= end:
            mid = start + (end - start) / 2
            if target <= arr[mid]:
                if (mid - 1 < start) or (mid - 1 >= start and arr[mid - 1] <= target):
                    return mid
                end = mid - 1
            else:
                # n >= arr[mid]
                start = mid + 1

        return -1

Revelation:

  • Try to build this longest increasing subsequence.
  • If current num is greater than the last element of the increasing_subseq, so we just append the current num to end of the increasing_subseq.
  • if current num less than greater than the last element of the increasing_subseq, we try to find a place i at where increasing_subseq[i - 1] <= current num <= increasing_subseq[i], then use the current num to update the increasing_subseq[i], which can make the increasing_subseq smaller and smaller.

  • For example, the current num is 9, and current increasing_subseq = [3, 10], we find the i = 1, which make increasing[1 - 1] <= 9 <= increasing_subseq[1], so we use '9' to update the '10', after updating the increasing_subseq become to [3, 9].

  • Another example, the current num is 3, and the current increasing_subseq = [1, 4, 10], after updating, the increasing_subseq become to [1, 3, 10], which give the future coming elements more 'space' to grow.
  • Because when we build the increasing_subseq, we update the increasing_subseq based on the element's order, so the elements of the increasing_subseq is sorted. So we can apply binary search to find the position.

Note:

  • Time complexity = O(nlgn), n is the number of elements in the given nums.

results matching ""

    No results matching ""