0
点赞
收藏
分享

微信扫一扫

C++刷题之旅(62)动态规划

毅会 2022-04-19 阅读 46
c++leetcode

LeetCode算法入门(第六十二天)

动归

5.最长回文子串

在这里插入图片描述
首先确定dp[i][j]数组的含义:表示s[i…j]是否为回文子串;
初始化dp数组,一个字符是回文子串,同时初始化回文子串的最大长度为1
状态转移公式:当s[i]==s[j]时,s[i…j]是否为回文子串由s[i+1…j-1]是否为回文子串决定,所以dp[i][j]=dp[i+1][j-1]决定

外层循环控制参与判断回文子串的字符串长度,内层循环判断具体区间内的字符串是否为回文子串

class Solution {
public:
    string longestPalindrome(string s) {
       int n = s.size();
       if(n < 2){
           return s;
       }

       int maxLen = 1;  //一个字符是回文子串
       int begin = 0;
        //dp[i][j] 表示s[i...j]是否为回文子串
       vector<vector<int>> dp(n, vector<int>(n));
       for(int i = 0; i < n; i++){
           dp[i][i] = true; //一个字符是回文子串
       }

       for(int L = 2; L <= n; L++){
           for(int i = 0; i < n; i++){  
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
               int j = L + i -1;
               if(j >= n){
                   break;
               }

               if(s[i] != s[j]){
                   dp[i][j] = false;
               }else{
                   if(j - i < 3){  //0,1,2个字符子串都是回文子串
                       dp[i][j] = true;
                   }else{
                       dp[i][j] = dp[i+1][j-1];   //s[i...j]是否为回文子串由s[i+1...j-1]是否为回文子串决定
                   }
               }
               //只要 dp[i][L] == true 成立,就表示子串 s[i...L] 是回文,此时记录回文长度和起始位置
               if(dp[i][j] && j - i + 1 > maxLen){
                   maxLen = j - i +1;
                   begin = i;
               }
           }
       }
       return s.substr(begin, maxLen);
    }
};

413.等差数列划分

在这里插入图片描述

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) {
        vector<int> dp(nums.size(), 0);  //dp[i] nums数组中的第i+1个数组成的等差数列的个数
        int result = 0;
        for(int i = 2; i < nums.size(); i++){
            if(nums[i] - nums[i-1] == nums[i-1] - nums[i-2]){   //当符合等差条件时,才递推
                dp[i] = dp[i-1] + 1;    //比i-1时,多了一个本身
                result += dp[i];    //结果为符合条件的dp数组的值的和
            }
        }

        return result;

    }
};

91.解码方法

在这里插入图片描述

class Solution {
public:
    int numDecodings(string s) {
        vector<int> dp(s.length() + 1, 0);  //dp[i]表示s[1...i]个字符的解码情况
        dp[0] = 1;  //题目给的是非空字符串,但为了状态转移 初始化dp[0]为1
        for(int i = 1; i <= s.length(); i++){
            if(s[i-1] != '0'){   //使用一个字符,对s[i]进行解码
                dp[i] = dp[i-1];
            }
            if(i > 1 && s[i-2] != '0' && (10*(s[i-2] - '0') + (s[i-1] - '0') <= 26)){  //使用两个字符,即s[i-1]s[i]进行解码
                dp[i] += dp[i-2];   //需要加上使用一个字符时dp[i]的值
            }
        }

        return dp[s.length()];
    }
};


139.单词拆分

在这里插入图片描述

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> uset(wordDict.begin(), wordDict.end());  //用于判断字典中是否存在
        vector<bool> dp(s.size()+ 1, false);  //dp[i],字符串长度为i时,是否可拆分为一个或多个字典中出现的单词
        dp[0] = true; //尽管实际上dp[0]表示字符串为空,题目说了字符串不为空,但是dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递归的根基,dp[0]一定要为true,否则递归下去后面都都是false了

        for(int i = 1; i <= s.size(); i++){
            for(int j = 0; j < i; j++){
                string word = s.substr(j, i-j);
                if(uset.find(word) != uset.end() && dp[j]){  //如果dp[j]为true,且[j,i]这个区间的子串出现在字典中,那么dp[i]为true
                    dp[i] = true;
                }
            }
        }

        return dp[s.size()];
    }
};
举报

相关推荐

0 条评论