代码随想录打卡—day53—【子序列问题】— 9.1

1 1143. 最长公共子序列 

1143. 最长公共子序列

做的不顺利,没有深入的往下想,想了一半感觉卡住了,其实离答案很近了。

看完题解,AC代码:

class Solution {
public:
    int dp[1005][1005]; // dp[i][j]表示:text2的前i-1个串和text1的前j-1个串的最长公共子序列的长度

    /*
        我的思考:
        难点是:dp[i][j] 好像要知道上一次子串最长的子序列
        不能直接由于dp[i-1][j-1] 直接得出 还可以由dp[i-1][j] dp[i][j-1]
        需要知道之前这个格子对应的那个子串  
    */

    /*
        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]);a
            text1[0...i-2] 与text2[0...j-1]  text1[0..i-1]与text2[0..j-2]比较
        }

        dp[i][0] = 0
        dp[0][j] = 0
        其他都是0

        i++j++

        模拟
    */
    int longestCommonSubsequence(string text1, string text2) 
    {
        for(int j = 0; j < text2.size();j++)
            dp[0][j] = 0;
        for(int i = 0; i < text1.size();i++)
            dp[i][0] = 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()];
    }
};

2 1035. 不相交的线

1035. 不相交的线

和上一题一模一样。就是套了个壳子。AC代码:

class Solution {
public:
    // 也就是套个壳子的 最长公共子序列
    int dp[510][510]; // dp[i][j] 表示前i-1 和j-1序列的最长公共子序列长度
    /*
        略。见最长公共子序列。
    */

    int maxUncrossedLines(vector& nums1, vector& nums2) {
        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()];
    }
};

3 53. 最大子数组和

53. 最大子数组和

方法1:前缀和 + 一点技巧(好像是贪心):一个记录当前遍历位置前的最小前缀和。再利用一个int记录差值最大的值

我一开始只想到前缀和,但是O(n^2)超时,后来找到个题解加上一点技巧就可以在前缀和的 基础上降到O(n)。

class Solution
{
public:
    int maxSubArray(vector &nums)
    {
        int sum[100010];
        memset(sum,sizeof(sum),0);

        for(int i = 1; i <= nums.size();i++)  // 1...n
            sum[i] = sum[i-1] + nums[i-1];

        
        int low = INT_MAX;
        int dif = INT_MIN;
        for(int i = 0; i <= nums.size();i++) /// sum[j] - sum[i] 并且(j>i)求个max
        {
            // 一个记录当前遍历位置前的最小前缀和
            // 再利用一个int记录差值最大的值
            dif = max(dif , sum[i] - low);  // 目前最大的差值
            low = min(low , sum[i]); //必须要先更新max,再更新min,防止min和i重合
        }
        if(nums.size() == 1)return nums[0];
        return dif;
    }
};

方法2:动态规划法:

dp做起来比上面那个方法轻松一百倍,我服了,上面那个有点技巧还易错,dp就是个极简单的问题。ac:

class Solution {
public:
    // dp做一次
    int dp[100010]; // 以i结尾的连续子数组最大的和
    /*
        if(dp[j-1] >  0)
            dp[j] = dp[j-1] + nums[j];
        else dp[j] = nums[j];

        dp[0] = nums[0]

        j++;
    */
    int maxSubArray(vector& nums) {
        dp[0] = nums[0];
        int ans = dp[0];
        for(int j = 1; j < nums.size();j++)
        {
            if(dp[j-1] >  0)
                dp[j] = dp[j-1] + nums[j];
            else dp[j] = nums[j];
            ans = max(ans,dp[j]);
        }
        return ans;
    }
};

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