[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. 判断子序列 文章解释题目:
给定字符串 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. 编辑距离
自己看到题目的第一想法
虽然看视频上一堆人说秒了、秒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];
}
}
自己实现过程中遇到哪些困难
无,重点是思路很妙。 动态规划的难点在于确定递推公式,以及确定递推公式后的初始化。