代码随想录Day38-动态规划:力扣第1035m、53m、392e、115h、583m题

1035. 不相交的线

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:15m11s

思路

dp数组:二维dp,dp[i][j]表示nums1[:i]和nums2[:j]的最大连线数。
状态转移:当nums1[i]==nums2[j]时,让这两个数连线一定是当前最优的情况,所以连线数就等于dp[i - 1][j - 1] + 1;当不相等时,连线数就等于去掉nums1[i]或者nums2[j]的连线数中的最大值。

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( m n ) O(mn) O(mn)
C++代码
class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 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;
                else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        return dp[nums1.size()][nums2.size()];
    }
};

方法二:动态规划+滚动数组

用时:18m

思路

方法一可以用滚动数组优化空间,但是由于数组更新的时候会覆盖原来dp[i-1][j-1]的值,所以需要中间变量临时存储方法一中的dp[i-1][j-1]的值,由于当前dp[i][j]的值对于下一个位置也是所需要的值,在更新当前dp[i][j]的值时也需要先存储,所以就需要两个临时变量。
更新dp[i][j]的值时,首先用tmp2记录当前dp值,然后更新当前dp值,注意,如果是相等的情况,需要用到tmp1更新,更新后,由于要移动到下一个位置,将tmp2赋值给tmp1。
注意内层循环结束后,tmp1要移到开头。

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
        vector<int> dp(nums2.size() + 1, 0);
        int tmp1 = 0, tmp2 = 0;
        for (int i = 1; i <= nums1.size(); ++i) {
            tmp1 = dp[0];  // 注意!
            for (int j = 1; j <= nums2.size(); ++j) {
                tmp2 = dp[j];
                if (nums1[i - 1] == nums2[j - 1]) dp[j] = tmp1 + 1;
                else dp[j] = max(dp[j - 1], dp[j]);
                tmp1 = tmp2;
            }
        }
        return dp[nums2.size()];
    }
};

看完讲解的思考

无。

代码实现遇到的问题

本题滚动数组优化空间有点绕,一开始还以为只用一个临时变量,想了半天才发现得用两个变量,然后一开始还没讲tmp1移至开头。


53m. 最大子序和

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:13m38s

思路

dp数组:dp[i]表示以nums[i]为结尾的连续子数组的最大和。
状态转移:对于nums[i],有两种情况,一是nums[i]连接上nums[i-1]的子数组,二是nums[i]重新开头作为子数组,最大和为两者的最大值。

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int dp = 0, res = INT_MIN;
        for (int& n : nums) {
            dp = max(dp + n, n);
            if (dp > res) res = dp;
        }
        return res;
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


392e. 判断子序列

题目链接
代码随想录文章讲解链接

方法一:双指针

思路
  • 时间复杂度: O ( m + n ) O(m+n) O(m+n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
C++代码
class Solution {
public:
    bool isSubsequence(string s, string t) {
        int idx1 = 0, idx2 = 0;
        while (idx1 < s.length() && idx2 < t.length()) {
            if (s[idx1] == t[idx2++]) ++idx1;
        }
        return idx1 == s.length();
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


115h. 不同的子序列

题目链接
代码随想录文章讲解链接

方法一:

用时:

思路
  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()
C++代码

方法二:

用时:

思路
  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()
C++代码

看完讲解的思考

代码实现遇到的问题


583m. 两个字符串的删除操作

题目链接
代码随想录文章讲解链接

方法一:动态规划

用时:12m58s

思路

dp数组:二维dp数组,dp[i][j]表示s[:i]的子序列中出现s[:j]的个数。
状态转移:

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( m n ) O(mn) O(mn)
C++代码
class Solution {
public:
    int numDistinct(string s, string t) {
        vector<vector<unsigned int>> dp(s.length() + 1, vector<unsigned int>(t.length() + 1, 0));
        for (int i = 0; i <= s.length(); ++i) {
            dp[i][0] = 1;
            for (int j = 1; j <= i && j <= t.length(); ++j) {
                if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                else dp[i][j] = dp[i - 1][j];
            }
        }
        return int(dp[s.length()][t.length()] % (1000000000 + 7));
    }
};

方法二:动态规划+滚动数组

用时:8m28s

思路

方法一的空间优化版本。

  • 时间复杂度: O ( m n ) O(mn) O(mn)
  • 空间复杂度: O ( n ) O(n) O(n)
C++代码
class Solution {
public:
    int numDistinct(string s, string t) {
        vector<unsigned int> dp(t.length() + 1, 0);
        dp[0] = 1;
        for (int i = 1; i <= s.length(); ++i) {
            for (int j = min(i, int(t.length())); j > 0; --j) {
                if (s[i - 1] == t[j - 1]) dp[j] += dp[j - 1];
            }
        }
        return int(dp[t.length()] % (1000000000 + 7));
    }
};

看完讲解的思考

无。

代码实现遇到的问题

无。


最后的碎碎念

二维dp刷出手感了,dp数组的含义基本都差不多,关键点还是在于状态转移。

你可能感兴趣的:(代码随想录,动态规划,leetcode,算法,c++)