代码随想录算法训练营第四十六天| 53. 最大子数组和、392. 判断子序列、583. 两个字符串的删除操作、583. 两个字符串的删除操作、72. 编辑距离

[LeetCode] 53. 最大子数组和
[LeetCode] 53. 最大子数组和 文章解释

[LeetCode] 53. 最大子数组和 视频解释

题目:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 

是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 10^5
  • -104 <= nums[i] <= 10^4

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

[LeetCode] 53. 最大子数组和 

自己看到题目的第一想法

    1. 遍历数组,累加数组元素的值到 sum,将 sum 和最大和 maxSum 做对比, 如果 maxSum 没有初始化或者 sum 更大, 则更新 maxSum 的值。

    2. 动态规划,dp[nums.length], dp[i] 表示以 nums[i] 为结尾的字串中,子串的最大和。因此 dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); 拿以前一个元素结尾的字串的最大和,加上 nums[i], 如果和比 nums[i] 大,就依赖 dp[i - 1], 否则不依赖 dp[i - 1],因为 nums[i] 结尾就已经是最大了。

看完代码随想录之后的想法

class Solution {
    public int maxSubArray(int[] nums) {
        // dp[i] 表示以 nums[i] 为结尾的连续字串中,和最大的连续字串
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int result = dp[0];
        for (int i = 1; i < nums.length; i++) {
            if (dp[i - 1] <= 0) {// dp[i - 1] <= 0 => dp[i - 1] + nums[i] <= nums[i], 取 nums[i]
                dp[i] = nums[i];
            } else {
                dp[i] = dp[i - 1] + nums[i]; // dp[i - 1] > 0 => dp[i - 1] + nums[i] > nums[i], 取 dp[i - 1] + nums[i]
            }
            // dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);// 这个效率会低一些, 因为每次都要做加法操作
            if (result < dp[i]) {
                result = dp[i];
            }
        }
        return result;
    }
}
class Solution {
    public int maxSubArray(int[] nums) {
        int sum = 0;
        Integer result = null;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            if (result == null || result < sum) {
                result = sum;
            }
            if (sum < 0) {
                sum = 0;
            }
        }
        return result;
    }
}

// class Solution {
//     public int maxSubArray(int[] nums) {
//         int sum = nums[0];
//         int result = sum;
//         for (int i = 1; i < nums.length; i++) {
//             if (sum < 0) {
//                 sum = 0;
//             }
//             sum += nums[i];
//             if (result < sum) {
//                 result = sum;
//             }
//         }
//         return result;
//     }
// }

自己实现过程中遇到哪些困难

    对于如何将 sum 清 0 脑子里不是那么的清晰,总体简单。

[LeetCode] 392. 判断子序列
[LeetCode] 392. 判断子序列 文章解释

[LeetCode] 392. 判断子序列 视频解释

题目:

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace""abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

致谢:

特别感谢 @pbrother 添加此问题并且创建所有测试用例。

示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

提示:

  • 0 <= s.length <= 100
  • 0 <= t.length <= 10^4
  • 两个字符串都只由小写字符组成。

[LeetCode] 392. 判断子序列 

自己看到题目的第一想法

    先定义 dp 数组,dp[i][j] 表示以 i  - 1 为结尾的 s 的字串,是否是 一 j - 1 为结尾的 t 的字串的子序列. 

    但是死活想不到如果当前元素不存在,就当作把 t 中的字符删掉,这样 dp 递推公式就容易想了!

看完代码随想录之后的想法

class Solution {
    public boolean isSubsequence(String s, String t) {
        // dp[i][j] 表示以 i  - 1 为结尾的 s 的字串,是否是 一 j - 1 为结尾的 t 的字串的子序列. 
        int[][] dp = new int[s.length() + 1][t.length() + 1];
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = dp[i][j - 1];// 把 t.charAt(j) 删掉
                }
            }
        }
        return dp[s.length()][t.length()] == s.length();
    }
}
// 二维数组版本
class Solution {
    public boolean isSubsequence(String s, String t) {
        // dp[i][j] 表示以 i  - 1 为结尾的 s 的字串,是否是 一 j - 1 为结尾的 t 的字串的子序列. 
        boolean[][] dp = new boolean[s.length() + 1][t.length() + 1];
        dp[0][0] = true;
        for (int i = 0; i <= t.length(); i++) {
            dp[0][i] = true;
        }
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= t.length(); j++) {
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = dp[i][j - 1];// 把 t.charAt(j) 删掉
                }
            }
        }
        return dp[s.length()][t.length()];
    }
}
// 一维数组版本,没有太大区别
class Solution {
    public boolean isSubsequence(String s, String t) {
        // dp[i][j] 表示以 i  - 1 为结尾的 s 的字串,是否是 一 j - 1 为结尾的 t 的字串的子序列. 
        boolean[] dp = new boolean[t.length() + 1];
        for (int i = 0; i < dp.length; i++) {
            dp[i] = true;
        }
        for (int i = 1; i <= s.length(); i++) {
            dp[0] = false;
            boolean pre = i == 1;
            for (int j = 1; j <= t.length(); j++) {
                boolean current = dp[j];
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[j] = pre;
                } else {
                    dp[j] = dp[j - 1];// 把 t.charAt(j) 删掉
                }
                pre = current;
            }
        }
        return dp[t.length()];
    }
}
// 非动态规划版本
class Solution {
    public boolean isSubsequence(String s, String t) {
        int index = 0;
        for (int i = 0 ; i < s.length(); i++) {
            index = t.indexOf(s.charAt(i), index);
            if (index == -1 || (index == t.length() - 1 && i != s.length() - 1)) {
                return false;
            }
            index++;
        }
        return true;
    }
}

 自己实现过程中遇到哪些困难

    无

[LeetCode] 583. 两个字符串的删除操作
[LeetCode] 583. 两个字符串的删除操作 文章解释

[LeetCode] 583. 两个字符串的删除操作 视频解释

题目:

给定两个单词 word1 和 word2 ,返回使得 word1 和  word2 相同所需的最小步数

每步 可以删除任意一个字符串中的一个字符。

示例 1:

输入: word1 = "sea", word2 = "eat"
输出: 2
解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"

示例  2:

输入:word1 = "leetcode", word2 = "etco"
输出:4

提示:

  • 1 <= word1.length, word2.length <= 500
  • word1 和 word2 只包含小写英文字母

[LeetCode] 583. 两个字符串的删除操作 

自己看到题目的第一想法

    很难~完全没有头绪。。。

看完代码随想录之后的想法

    和编剧距离混在一起啦, 这里不能修改,EiH EiH EiH。

class Solution {
    public int minDistance(String word1, String word2) {
        // dp[i][j] 表示以 i - 1 为结尾的 word1 子串和以 j - 1 为结尾的 word2 子串,要变成相等的字串需要的最小操作数
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 0 ; i <= word2.length(); i++) {
            dp[0][i] = i; 
        }
        for (int i = 0; i <= word1.length(); i++) {
            dp[i][0] = i;
        }
        for (int i = 1; i <= word1.length(); i++) {
            for (int j = 1; j <= word2.length(); j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    // dp[i - 1][j]: 删除s[i]
                    // dp[i][j - 1]: 删除t[j]
                    dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1;
                }
            }
        }
        return dp[word1.length()][word2.length()];
    }
}

自己实现过程中遇到哪些困难

    无,代码实现是比较简单的,不怎么绕。

[LeetCode] 72. 编辑距离
[LeetCode] 72. 编辑距离 文章解释

[LeetCode] 72. 编辑距离 视频解释

[LeetCode] 72. 编辑距离 

自己看到题目的第一想法

    虽然看视频上一堆人说秒了、秒AC。。。我觉得我一点思路都没有啊。。。

看完代码随想录之后的想法

    确实挺简单的。。。

class Solution {
    public int minDistance(String word1, String word2) {
        char[] word1Chars = word1.toCharArray();
        char[] word2Chars = word2.toCharArray();

        int[][] dp = new int[word1Chars.length + 1][word2Chars.length + 1];

        for (int i = 1; i <= word2Chars.length; i++) {// 注意这里是 <=, 等于别忘记了
            dp[0][i] = i;
        }
        for (int i = 1; i <= word1Chars.length; i++) {
            dp[i][0] = i;
        }
        for (int i = 1; i <= word1Chars.length; i++) {
            for (int j = 1; j <= word2Chars.length; j++) {
                if (word1Chars[i - 1] == word2Chars[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1;
                }
            }
        }
        return dp[word1Chars.length][word2Chars.length];
    }
}

自己实现过程中遇到哪些困难

    无,重点是思路很妙。 动态规划的难点在于确定递推公式,以及确定递推公式后的初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值