动态规划-子序列问题

最长递增子序列

题目:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
例如:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
Solution:
Step 1: dp[i]表示i之前包括i的最长上升子序列。

Step 2: 状态转移方程:
if (nums[i] > nums[j])
dp[i] = max(dp[i], dp[j] + 1);
其中,j 的范围是(0,i-1).

Step 3: 初始化:每一个i,对应的dp[i]起始大小至少都是是1.

Step 4: 遍历顺序:
dp[i] 是由0到i-1各个位置的最长升序子序列推导而来,那么遍历i一定是从前向后遍历。

Step 5: 敲代码

 int lengthOfLIS(vector<int>& nums) {
        if (nums.size() <= 1) 
        	return nums.size();
        vector<int> dp(nums.size(), 1);
        int result = 0; //维持最长的子序列
        for (int i = 1; i < nums.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j])
                	dp[i] = max(dp[i], dp[j] + 1);
            }
            if (dp[i] > result) 
            	result = dp[i]; // 取长的子序列
        }
        return result;
    }

最长连续递增子序列

题目:给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
例如:
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
Solution:
Step 1: dp[i]: 以下标i为结尾的数组的连续递增的子序列长度为dp[i]。
Step 2: 递推公式:
if nums[i + 1] > nums[i],那么以 i+1 为结尾的数组的连续递增的子序列长度 一定等于 以i为结尾的数组的连续递增的子序列长度 + 1 。
也就是说:
if (nums[i+1]>nums[i]) dp[i+1]=dp[i]+1;
Step 3: 初始化:
以下标i为结尾的数组的连续递增的子序列长度最少也应该是1,即就是nums[i]这一个元素。所以dp[i]应该初始1;
Step 4: 敲代码

int findLengthOfLCIS(vector<int>& nums) {
        if (nums.size() == 0) 
        	return 0;
        int result = 1;
        vector<int> dp(nums.size()+1,1);
        for (int i = 0; i < nums.size() - 1; i++) {
            if (nums[i + 1] > nums[i]) { // 连续记录
                dp[i + 1] = dp[i] + 1;
            }
            if (dp[i + 1] > result) 
            	result = dp[i + 1];
        }
        return result;
    }

最长重复子数组

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
例如:
输入:A: [1,2,3,2,1] B: [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3, 2, 1] 。
Solution :
Step 1: dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。
Step 2: dp[i][j]的状态只能由dp[i - 1][j - 1]推导出来。即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;根据递推公式可以看出,遍历i 和 j 要从1开始.
Step 3: 由dp[i][j]的定义,dp[i][0] 和dp[0][j]其实都是没有意义的,但dp[i][0] 和dp[0][j]要初始值,因为 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1;
所以dp[i][0] 和dp[0][j]初始化为0。
Step 4: 敲代码

int findLength(vector<int>& A, vector<int>& B) {
        vector<vector<int>> dp (A.size() + 1, vector<int>(B.size() + 1, 0));
        int result = 0;
        for (int i = 1; i <= A.size(); i++) {
            for (int j = 1; j <= B.size(); j++) {
                if (A[i - 1] == B[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                if (dp[i][j] > result) 
                	result = dp[i][j];
            }
        }
        return result;

最长公共子序列

题目:给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
例如:
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace”,它的长度为 3。
Step 1: dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j].
Step 2: if text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1; if text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。就是dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
Step 3:
dp[i][0] = 0, dp[0][j]也是0。
Step 4: 敲代码

 int longestCommonSubsequence(string text1, string text2) {
        vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
        for (int i = 1; i <= text1.size(); i++) {
            for (int j = 1; j <= text2.size(); j++) {
                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]);
                }
            }
        }
        return dp[text1.size()][text2.size()];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SCUT慎独

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值