当前位置:   article > 正文

代码随想录算法训练营第四十七天|1143.最长公共子序列、 1035.不相交的线、53. 最大子序和、392.判断子序列

代码随想录算法训练营第四十七天|1143.最长公共子序列、 1035.不相交的线、53. 最大子序和、392.判断子序列

1143.最长公共子序列

在这里插入图片描述

题目链接:1143.最长公共子序列
文档讲解:代码随想录
状态:一开始没想明白为啥要 max(dp[i - 1][j], dp[i][j - 1])

思路:
如果text1[i - 1] 与 text2[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;

如果text1[i - 1] 与 text2[j - 1]不相同,那就看看text1[0, i - 2]与text2[0, j - 1]的最长公共子序列 和 text1[0, i - 1]与text2[0, j - 2]的最长公共子序列,取最大的。

即:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

题解:

    // 二维动态规划方法
    public int longestCommonSubsequence(String text1, String text2) {
        char[] chars1 = text1.toCharArray();
        char[] chars2 = text2.toCharArray();
        int m = chars1.length;
        int n = chars2.length;

        // 创建二维dp数组,dp[i][j]表示text1前i个字符和text2前j个字符的最长公共子序列长度
        int[][] dp = new int[m + 1][n + 1];

        // 遍历每个字符,填充dp数组
        for (int i = 1; i <= chars1.length; i++) {
            for (int j = 1; j <= chars2.length; j++) {
                if (chars1[i - 1] == chars2[j - 1]) {
                    // 如果字符相等,则当前状态等于左上角状态加1
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 如果字符不相等,则当前状态等于上方和左方状态的最大值
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 返回最终结果,dp[m][n]即为最长公共子序列长度
        return dp[m][n];
    }

    // 一维动态规划方法(空间优化)
    public int longestCommonSubsequence2(String text1, String text2) {
        char[] chars1 = text1.toCharArray();
        char[] chars2 = text2.toCharArray();
        int n = chars2.length;

        // 创建一维dp数组,dp[j]表示text1前i个字符和text2前j个字符的最长公共子序列长度
        int[] dp = new int[n + 1];

        // 遍历每个字符,填充dp数组
        for (int i = 1; i <= chars1.length; i++) {
            int pre = dp[0]; // 保存左上角的值
            for (int j = 1; j <= chars2.length; j++) {
                int cur = dp[j]; // 当前dp[j]的值,在更新dp[j]之前保存它
                if (chars1[i - 1] == chars2[j - 1]) {
                    // 如果字符相等,则当前状态等于左上角状态加1
                    dp[j] = pre + 1;
                } else {
                    // 如果字符不相等,则当前状态等于上方和左方状态的最大值
                    dp[j] = Math.max(dp[j], dp[j - 1]);
                }
                pre = cur; // 更新pre为当前dp[j]的值
            }
        }

        // 返回最终结果,dp[n]即为最长公共子序列长度
        return dp[n];
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

1035.不相交的线

在这里插入图片描述

题目链接:1035.不相交的线
文档讲解:代码随想录
状态:还行

思路:
直线不能相交,这就是说明在字符串A中 找到一个与字符串B相同的子序列,且这个子序列不能改变相对顺序,只要相对顺序不改变,链接相同数字的直线就不会相交。
所以,本题说是求绘制的最大连线数,其实就是求两个字符串的最长公共子序列的长度!

题解:

class Solution {
    // 二维动态规划方法
    public int maxUncrossedLines(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        
        // 创建二维dp数组,dp[i][j]表示nums1前i个元素和nums2前j个元素能形成的最大不相交的线数
        int[][] dp = new int[m + 1][n + 1];

        // 遍历每个元素,填充dp数组
        for (int i = 1; i <= nums1.length; i++) {
            for (int j = 1; j <= nums2.length; j++) {
                if (nums1[i - 1] == nums2[j - 1]) {
                    // 如果元素相等,则当前状态等于左上角状态加1
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    // 如果元素不相等,则当前状态等于上方和左方状态的最大值
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        // 返回最终结果,dp[m][n]即为最大不相交的线数
        return dp[m][n];
    }

    // 一维动态规划方法(空间优化)
    public int maxUncrossedLines2(int[] nums1, int[] nums2) {
        int n = nums2.length;
        
        // 创建一维dp数组,dp[j]表示nums1前i个元素和nums2前j个元素能形成的最大不相交的线数
        int[] dp = new int[n + 1];

        // 遍历每个元素,填充dp数组
        for (int i = 1; i <= nums1.length; i++) {
            int pre = dp[0]; // 保存左上角的值
            for (int j = 1; j <= nums2.length; j++) {
                int cur = dp[j]; // 当前dp[j]的值,在更新dp[j]之前保存它
                if (nums1[i - 1] == nums2[j - 1]) {
                    // 如果元素相等,则当前状态等于左上角状态加1
                    dp[j] = pre + 1;
                } else {
                    // 如果元素不相等,则当前状态等于上方和左方状态的最大值
                    dp[j] = Math.max(dp[j], dp[j - 1]);
                }
                pre = cur; // 更新pre为当前dp[j]的值
            }
        }

        // 返回最终结果,dp[n]即为最大不相交的线数
        return dp[n];
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

53. 最大子序和

在这里插入图片描述

题目链接:53. 最大子序和
文档讲解:代码随想录
状态:还行

思路:
dp[i]只有两个方向可以推出来:

dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列
nums[i],即:从头开始计算当前连续子序列和

题解:

   // 贪心算法:每次加上的数字如果不能使sum增加,那就从下个数字开始
    public int maxSubArray(int[] nums) {
        int max = nums[0]; // 初始化最大子数组和为数组的第一个元素
        int sum = 0; // 当前子数组和
        for (int num : nums) {
            sum += num; // 更新当前子数组和
            max = Math.max(max, sum); // 更新最大子数组和
            if (sum <= 0) {
                sum = 0; // 如果当前子数组和为负数或0,从下一个元素重新开始计算
            }
        }
        return max; // 返回最大子数组和
    }

    // 动态规划算法:dp[i]表示以第i个元素结尾的最大子数组和
    public int maxSubArray2(int[] nums) {
        int[] dp = new int[nums.length + 1]; // 创建dp数组,长度为nums.length+1
        dp[0] = nums[0]; // 初始化dp[0]为数组的第一个元素
        int max = nums[0]; // 初始化最大子数组和为数组的第一个元素
        for (int i = 1; i < nums.length; i++) {
            // dp[i]表示以第i个元素结尾的最大子数组和
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            // 更新最大子数组和
            max = Math.max(max, dp[i]);
        }
        return max; // 返回最大子数组和
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

392.判断子序列

在这里插入图片描述

题目链接:392.判断子序列
文档讲解:代码随想录
状态:so easy

思路:
可以双指针,也可以动态规划。

题解:

    // 双指针方法判断s是否为t的子序列
    public boolean isSubsequence(String s, String t) {
        // 将字符串s和t转换为字符数组
        char[] sChars = s.toCharArray();
        char[] tChars = t.toCharArray();

        // 初始化两个指针,分别指向sChars和tChars的起始位置
        int j = 0;

        // 遍历tChars数组
        for (int i = 0; i < tChars.length && j < sChars.length; i++) {
            // 如果当前字符相等,则移动指向sChars的指针
            if (tChars[i] == sChars[j]) {
                j++;
            }
        }

        // 如果j等于sChars的长度,说明s是t的子序列
        return j == sChars.length;
    }

    public boolean isSubsequence2(String s, String t) {
        char[] chars1 = s.toCharArray();
        char[] chars2 = t.toCharArray();
        int n = chars2.length;

        // 创建一维dp数组,dp[j]表示text1前i个字符和text2前j个字符的最长公共子序列长度
        int[] dp = new int[n + 1];

        // 遍历每个字符,填充dp数组
        for (int i = 1; i <= chars1.length; i++) {
            int pre = dp[0]; // 保存左上角的值
            for (int j = 1; j <= chars2.length; j++) {
                int cur = dp[j]; // 当前dp[j]的值,在更新dp[j]之前保存它
                if (chars1[i - 1] == chars2[j - 1]) {
                    // 如果字符相等,则当前状态等于左上角状态加1
                    dp[j] = pre + 1;
                } else {
                    // 如果字符不相等,则当前状态等于上方和左方状态的最大值
                    dp[j] = Math.max(dp[j], dp[j - 1]);
                }
                pre = cur; // 更新pre为当前dp[j]的值
            }
        }

        // 返回最终结果,dp[n]即为最长公共子序列长度
        return dp[n] == chars1.length;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号