标签 动态规划 下的文章

题目链接:编辑距离

给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

方法一:二维数组+动态规划

class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));

        for (int i = 0; i < dp.size(); i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j < dp[0].size(); j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i < dp.size(); i++) {
            for (int j = 1; j < dp[i].size(); j++) {
                // dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
                // if (word1[i - 1] == word2[j - 1]) {
                //     dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]);
                // }
                dp[i][j] = word1[i-1] == word2[j-1] ? dp[i-1][j-1] : min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
            }
        }
        return dp.back().back();
    }
};

题目链接:最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

方法一:二维数组+动态规划

class Solution {
public:
    int f[1010][1010];
    int longestCommonSubsequence(string text1, string text2) {
        int n = text1.size();
        int m = text2.size();
        for (int i = 0;i < n;i++) {
            for (int j = 0;j < m;j++) {
                f[i+1][j+1] = text1[i] == text2[j] ? f[i][j] + 1 : max(f[i][j+1],f[i+1][j]); 
            }
        }
        return f[n][m];
    }
};

题目链接:单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

方法一:动态规划

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        vector<bool> dp(s.size()+1);
        dp[0] = true;
        for (int i = 1;i <= s.size();i++) {
            for (auto& word:wordDict) {
                int sz = word.size();
                if (i - sz >= 0 && s.substr(i-sz,sz) == word) 
                    dp[i] = dp[i] || dp[i-sz];
            }
        }
        return dp[s.size()];
    }
};

题目链接:分割等和子集

给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

方法一:动态规划+二维数组

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        vector dp(nums.size() + 1, vector<int> (2e4 + 10, 0));
        double sum = 0;
        for (auto x : nums) {
            sum += x;
        }
        double target = sum / 2;
        for (int i = 0;i < nums.size();i++) {
            for (int j = 0;j <= target;j++) {
                if (j < nums[i]) {
                    dp[i+1][j] = dp[i][j];
                }else 
                    dp[i + 1][j] = max(dp[i][j], dp[i][j - nums[i]] + nums[i]);
            }
        }
        return dp[nums.size()][target] == target;
    }
};

方法二:动态规划+一维数组

//一维优化
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        vector<int> dp(2e4 + 10, 0);
        double sum = 0;
        for(int i = 0;i < nums.size(); ++i)
            sum += nums[i];
        double target = double(sum / 2);

        for(int i = 0; i < nums.size(); ++i)
            for(int j = target;j >= nums[i]; --j)
                    dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
        
        return dp[target] == target;
    }
};

题目链接:完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。

方法一:动态规划

class Solution {
public:
    int numSquares(int n) {
        int f[10010];
        //f[0] = 0;
        for (int i = 1;i <= n;i++) {
            f[i] = i;
            for (int j = 1;j * j <= i;j++) {
                f[i] = min(f[i],f[i-j*j]+1);
            }
           // f[i] = minn + 1;
        }
        return f[n];
    }
};