最长重复子数组 && 最长公共子序列

二者区别:一个要求连续,一个可以不连续

最长重复子数组 && 最长公共子序列_第1张图片

  1. dp[i][j]:以下标i-1结尾的A和下标j-1结尾的B,最长重复子数组长度为dp[i][j]
  2. 递推公式:当A[i - 1] == B[j - 1]dp[i][j] = dp[i-1][j-1] + 1,故i和j得从1开始遍历。
  3. 初始化
    由dp[i]数组的含义可知,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。
  4. 确定递推顺序
    外层for遍历A,内层for遍历B
  5. 举例推导dp数组
class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        vector<vector<int> > dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));

        for(int i = 0; i < nums1.size(); i++)
            dp[i][0] = 0;
        
        for(int i = 0; i < nums2.size(); i++)
            dp[0][i] = 0;

        
        int res = 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] > res) res = dp[i][j];
            }
        }

        return res;
    }
};

滚动数组

class Solution {
public:
    int findLength(vector<int>& nums1, vector<int>& nums2) {
        //vector > dp(nums1.size() + 1, vector(nums2.size() + 1, 0));

        vector<int> dp(nums2.size() + 1, 0);

        //for(int i = 0; i < nums1.size(); i++)
            //dp[i][0] = 0;
        
       // for(int i = 0; i < nums2.size(); i++)
          //  dp[0][i] = 0;

        
        int res = 0;

        for(int i = 1; i <= nums1.size(); i++){
            for(int j = nums2.size(); j >= 1; j--){
                if(nums1[i-1] == nums2[j-1]){
                    dp[j] = dp[j-1] + 1;
                }else dp[j] = 0;  //!!!置为0

                if(dp[j] > res) res = dp[j];
            }
        }

        return res;
    }
};

最长重复子数组 && 最长公共子序列_第2张图片

与上一题的区别就是不要求连续,但是相对顺序不能变

  1. dp[i][j] 表示以i-1结尾的A数组和j-1结尾的B数组之间的最长公共子序列的长度
  2. 递推公式:若text1[i-1] == text2[i-1],则有dp[i][j] = dp[i-1][j-1] + 1;否则话 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        vector<vector<int> > dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
        int res = 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]);

                if(dp[i][j] > res) res = dp[i][j];
            }
        }

        return res;
    }
};

最长重复子数组 && 最长公共子序列_第3张图片

这题与最长公共子序列很像,只是说t是可以跳跃元素的,而s不能
故当s[i-1] != t[j-1])时,dp[i][j] = dp[i][j-1]。(注意不是dp[i][j] = max(dp[i][j-1], dp[i-1][j])

class Solution {
public:
    //用最长重复子序列去求解
    bool isSubsequence(string s, string t) {
        vector<vector<int> > dp(s.size()+1, 
        vector<int>(t.size()+1, 0));

        int maxLen = INT_MIN;

        for(int i = 1; i <=s.size(); i++){
            for(int j = 1; j <= t.size(); j++){
                if(s[i-1] == t[j-1]){
                    dp[i][j] = dp[i-1][j-1] + 1;
                }
                else dp[i][j] = dp[i][j-1];

                
            }
        }

        
        
        return dp[s.size()][t.size()] == s.size();
         
    }
};

用双指针

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int i = 0, j = 0;
        int res = 0;

        while(i < s.size() && j < t.size()){
            if(s[i] == t[j]){
                i++;
                res++;
            }

            j++;
        }

        return res == s.size();
    }
};

你可能感兴趣的:(动态规划,LeetCode,homebrew,linux,jupyter)