LIS 与LCS

LIS与LCS是动态规划中最常见的两种情况,LIS也就是最长上升子序列,而LCS是最长公共子序列。

在解决这个问题之前,先要明白为什么是序列,举个例子来说明,在数组 [1,2,3,4,5,6]中,[2,3,5]就是其子序列,也就是说,子序列其实就是数组中存在先后顺序,但不强调连续的子数组。那么,在了解了序列是什么之后,就来看一下题吧。

首先是LIS:即求最长上升子序列。

那么既然是动态规划,那就要去找状态转移方程,那么,我可以设置为对于dp【j】表示以nums【j】为结尾的递增子序列的长度

那么这时,就可以尝试用代码来实现:

class Solution:
    def lengthOfLIS(self, nums):
        nums=[-1000000]+nums
        n=len(nums)
        dp=[0]*len(nums)
        for i in range(1,n):
            for j in range(i):
                if nums[i]>nums[j]:
                    dp[i]=max(dp[i],dp[j]+1)

        return (max(dp))

这里就是用dp数组表示当前的最大上升子序列的长度的代码,那么对于这个来处理的方法就是如下,首先遍历nums数组,然后再遍历nums【i】之前的所有数字nums【j】若是当前的数字nums【i】的值比nums【j】大,那么就二者进行比较,此时运用max数组来对dp【i】和dp【j】进行比较,来决定增加,最后输出dp数组中的最大值,最后,就可以得到答案。

但是,这个代码只是O(n**2)的复杂度,只可以处理10**4级别的数据,因此,需要去优化代码,

那么如何去优化呢,可以尝试如下的方案,将其优化到O(nlogn)的级别,那么如何来处理?

便是直接去遍历数组,维护一个单调递增的序列即可

class Solution:
    def lengthOfLIS(self, nums):
        from bisect import bisect_left
        n=len(nums)
        dp=[]
        for i in range(n):
            if not dp or nums[i]>dp[-1]:
                dp.append(nums[i])
            else:
                idx=bisect_left(dp,nums[i])
                dp[idx]=nums[i]
        return len(dp)

在这里其实就是在维护一个单带增加的序列,因为从第一个数开始,由于求递增序列,在遍历的过程中,若是当前的数比dp的最后一项大,那么这个数一定会让序列增加,而若是这个数字小于等于dp数组的最后一个数,那么这个数一定不会让递增子序列的数字增加,这时,就使用二分查找来更新dp数组,将这个数字替换到对应的位置,这样子就可以维护一个dp数组,最后dp数组的长度就是最大dp递增子序列。

这个就是一个更优的题解。

而LCS则是去求最长公共子序列

要求解这道题,就要去找状态转移方程,这里由于有两个字符串,那么就要使用二维dp,dp【i】【j】表示分别到i为止和到j为止最长公共子序列的长度,那么接着就是去找状态转移方程。这道题的状态转移方程就是

dp【i】【j】=dp【i-1】【j-1】 --------当str1【i】==str2【j】的时候;

dp【i】【j】=max(dp【i-1】【j】,dp【i】【j-1】)--------其他情况。

那么在这里就可以写出代码了

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        dp=[[0]*(len(text2)+1) for i in range(len(text1)+1)]
        # for i in dp:
        #     print(i)
        for i in range(1,len(text1)+1):
            for j in range(1,len(text2)+1):
                if text1[i-1]==text2[j-1]:
                    dp[i][j]=dp[i-1][j-1]+1
                else:
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1])
        # for i in dp:
        #     print(i)

        return dp[len(text1)][len(text2)]

这里就是关于这道题的实现。

那就到这里了。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值