【动态规划——子序列】

这里写目录标题

  • 题目:300. 最长递增子序列
    • 实现算法:动规
    • 自我实现
  • 题目:674. 最长连续递增序列
    • 实现算法:
    • 自我实现
  • 题目:718. 最长重复子数组
    • 实现算法:
    • 自我实现
  • 题目:1143. 最长公共子序列
    • 实现算法:
    • 自我实现
    • 做题心得
    • 做题心得

题目:300. 最长递增子序列

链接: leetcode题目链接

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4

示例3:
输入:nums = [7,7,7,7,7,7,7]
输出:1

提示:
1).1 <= nums.length <= 2500
2).-10^4 <= nums[i] <= 10^4

实现算法:动规

dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

class Solution {
public:
    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;
    }
}; 

p.s.

自我实现

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(),1);
        int body=1;
        for(int i=1;i<nums.size();i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]) dp[i]=max(dp[j]+1,dp[i]);
            }
            if(dp[i]>body) body=dp[i];
        }
        return body;
    }
};

p.s.

题目:674. 最长连续递增序列

链接: leetcode题目链接

给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], …, nums[r - 1], nums[r]] 就是连续递增子序列。

示例 1:
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。

示例 2:
输入:nums = [2,2,2,2,2]
输出:1
解释:最长连续递增序列是 [2], 长度为1。

提示:
1).1 <= nums.length <= 104
2).-109 <= nums[i] <= 109

实现算法:

dp[i]:以下标i为结尾的连续递增的子序列长度为dp[i]。

方法思路:

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

p.s.

自我实现

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        vector<int> dp(nums.size(),1);
        int count=1;
        for(int i=1;i<nums.size();i++){
            if(nums[i]>nums[i-1]) dp[i]=dp[i-1]+1;
            if(count<dp[i]) count=dp[i];
        }
        return count;
    }
};

p.s.

题目:718. 最长重复子数组

链接: leetcode题目链接

给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。

示例 1:
输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7]
输出:3
解释:长度最长的公共子数组是 [3,2,1] 。

示例 2:
输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0]
输出:5

提示:
1).1 <= nums1.length, nums2.length <= 1000
2).0 <= nums1[i], nums2[i] <= 100

实现算法:

dp[i][j] :以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
        int result = 0;
        for (int i = 1; i <= nums1.size(); i++) {
            for (int j = 1; j <= nums2.size(); j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                if (dp[i][j] > result) result = dp[i][j];
            }
        }
        return result;
    }
};

p.s.
两个数组比较,一般都设为以下标i - 1为结尾的A,和以下标j - 1为结尾的B,方便初始化

自我实现

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        int count=0;
        vector<vector<int>> dp(nums1.size(),vector<int>(nums2.size(),0));
        for(int i=0;i<nums1.size();i++){
            if(nums1[i]==nums2[0]) dp[i][0]=1;
            if(dp[i][0]>count) count=dp[i][0];
        }
        for(int j=0;j<nums2.size();j++){
            if(nums2[j]==nums1[0]) dp[0][j]=1;
            if(dp[0][j]>count) count=dp[0][j];
        }
        
        for(int i=1;i<nums1.size();i++){
            for(int j=1;j<nums2.size();j++){
                if(nums1[i]==nums2[j]) dp[i][j]=dp[i-1][j-1]+1;
                //else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                if(dp[i][j]>count) count=dp[i][j];
            }
            
        }
        return count;
    }
};

p.s.

题目:1143. 最长公共子序列

链接: leetcode题目链接

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。

示例 2:
输入:text1 = “abc”, text2 = “abc”
输出:3
解释:最长公共子序列是 “abc” ,它的长度为 3 。

示例3:
输入:text1 = “abc”, text2 = “def”
输出:0
解释:两个字符串没有公共子序列,返回 0 。

提示:
1).1 <= text1.length, text2.length <= 1000
2).text1 和 text2 仅由小写英文字符组成。

实现算法:

dp[i][j]:长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j]


class Solution {
public:
    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()];
    }
};

p.s.

自我实现


p.s.

做题心得

做题心得

你可能感兴趣的:(动态规划,算法)