leetcode -- Longest Increasing Subsequence -- DP 重点常考

https://leetcode.com/problems/longest-increasing-subsequence/

思路1 n^2

参考http://bookshadow.com/weblog/2015/11/03/leetcode-longest-increasing-subsequence/

动态规划(Dynamic Programming)

状态转移方程:

dp[x] = max(dp[x], dp[y] + 1) 其中 y < x 并且 nums[x] > nums[y]

即在求dp[x]的时候,比较x之前的元素y以及其对应的dp[y], 找到一个最大的dp[y] + 1, y

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        dp = [1] * size
        for x in range(size):
            for y in range(x):
                if nums[x] > nums[y]:
                    dp[x] = max(dp[x], dp[y] + 1)
        return max(dp) if dp else 0

思路2 nlogn

binary search

这里类似于插入排序,这里用BS不是找到一个target数的index,而是找到一个target所能插入的index。所以不返回mid, 返回low,并且也不用对等号进行判断。

就是用dp数组来维护一个升序数组,scan每一个数组值A[i],然后看A[i]是否能插入dp中,如果low >=len(dp), 那么就在dp末尾append; else 则替换dp[low] = A[i],因为这样替换并没有降低当前LIS的长度,并且还扩大increasing subsequence长度的增长空间

本质就是如果是个可以插入的值,例如dp = {2, 5}, A[i] = 3, 则替换最后一个值,降低increasing subsequence的最大值以扩大increasing subsequence长度的增长空间;如果A[i] = 6, 无法插入,那么就直接加入在dp末尾就行。这里如果只对,low>=len(dp)在dp末尾append,那么就不能修改搜索递增序列的最小值,使得[10,9,2,5,3,7,101,18]这样的输入,得到的结果是[10, 101]

这是一个trick。记住

code 参考 http://bookshadow.com/weblog/2015/11/03/leetcode-longest-increasing-subsequence/

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        dp = []
        for x in range(size):
            low, high = 0, len(dp) - 1
            while low <= high:
                mid = (low + high) / 2
                if dp[mid] >= nums[x]:
                    high = mid - 1
                else:
                    low = mid + 1
            if low >= len(dp):
                dp.append(nums[x])
            else:#这里在dp = [2,3], nums[x] = 1的情况下,会将dp变成[1,3], 虽然不是递增的seq,但是长度一样。
                dp[low] = nums[x]
        return len(dp)

自己重写code

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 0: return 0
        lis = []
        for i in xrange(len(nums)):
            if lis == []:
                lis.append(nums[i])
            else:
                low, high = 0, len(lis) - 1
                while low <= high:
                    mid = (low + high) / 2
                    if lis[mid] < nums[i]:#这里不要有等号
                        low = mid + 1
                    else:#等号放在这里,因为lis = [2], nums[i] = [2],这样的case不应该变成[2,2]
                        high = mid - 1
                if low == len(lis):#不是low == i
                    lis.append(nums[i])
                else:
                    lis[low] = nums[i]
        return len(lis)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值