力扣算法学习day38-2
53-最大子数组和-完全版-添加上了dp解法
题目
代码实现
class Solution {
// public int maxSubArray(int[] nums) {
// // 贪心,sum小于0,则与后面的数相加一定减小和,故sum小于0后,需要从新
// // 从下一个点开始计算sum。sum<0中对maxValue的判断是考虑答案为负数。
// int maxValue = Integer.MIN_VALUE;
// int sum = 0;
// int index = 0;
// while(index < nums.length){
// sum += nums[index];
// if(sum < 0){
// if(sum > maxValue){
// maxValue = sum;
// }
// index++;
// sum = 0;
// continue;
// }
// if(sum > maxValue){
// maxValue = sum;
// }
// index++;
// }
// return maxValue;
// }
// 代码优化,实际上sum的大小判定放在前面的话就不需要再在sum<0的时候判断负数情况了
// public int maxSubArray(int[] nums) {
// int maxValue = Integer.MIN_VALUE;
// int sum = 0;
// for(int i = 0;i < nums.length;i++){
// sum += nums[i];
// if(sum > maxValue){
// maxValue = sum;
// }
// if(sum < 0){
// sum = 0;
// }
// }
// return maxValue;
// }
public int maxSubArray(int[] nums) {
// dp:速度:2ms
// 思路:
// dp[i]:表示以第i个元素的结尾数组的子数组的最大子数组的和
// 思考方式1:dp[i-1]:代表i-1个元素的子数组的最大子数组的和,如果当前nums[i]+dp[i-1]比nums[i]还要小,说明i-1个元素
// 的数组的最大子数组和为负数,那么重新开始计数即可,如果nums[i]+dp[i-1]比nums[i]还要大,有两种情况,nums[i]
// 为正数,那么就是增加即可,如果nums[i]为负数,那么如果nums[i]+dp[i-1]大于0那么可以继续用于加,如果nums[i]+dp[i-1]
// 小于0了,那下一个数会自动从新开始计数,实际上这里还是用了贪心的思路。
// 思考方式2:也可以从定义来看,dp[i]表示以第i个元素的结尾数组的子数组的最大子数组的和,那么对于第i个数组的最大子数组的和
// 可以由i-1结尾加上第i个元素或单独取第i个元素两种情况,取最大的情况即可,这种理解更符合dp的方式。
int[] dp = new int[nums.length];
int maxLength = nums[0];
dp[0] = nums[0];
for(int i = 1;i < dp.length;i++){
dp[i] = Math.max(dp[i-1] + nums[i],nums[i]);
// System.out.print(dp[i]);
if(dp[i] > maxLength){
maxLength = dp[i];
}
}
return maxLength;
}
}
392-判断子序列
题目
代码实现
class Solution {
// 思路1:动态规划 速度 4ms
// public boolean isSubsequence(String s, String t) {
// // dp:
// // 思路:很简单,如果s是t的子序列,那么,说明s和t的最大公共子序列的长度一定为s的长度。
// char[] sList = s.toCharArray();
// char[] tList = t.toCharArray();
// int[][] dp = new int[tList.length+1][sList.length+1];
// for(int i = 1;i < dp.length;i++){
// for(int j = 1;j < dp[i].length;j++){
// if(tList[i-1] == sList[j-1]){
// dp[i][j] = dp[i-1][j-1] + 1;
// } else{
// dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
// }
// }
// }
// return dp[tList.length][sList.length] == sList.length;
// }
// 思路2:用指针扫描,速度 0ms
// public boolean isSubsequence(String s, String t) {
// char[] tList = t.toCharArray();
// char[] sList = s.toCharArray();
// int index = 0;// 用于记录上次元素的位置。
// for(int i = 0;i < sList.length;i++){
// boolean flag = false;
// for(int j = index;j < tList.length;j++){
// if(sList[i] == tList[j]){
// index = j+1;
// flag = true;
// break;
// }
// }
// if(!flag){// 没有找到
// return false;
// }
// }
// return true;
// }
// 思路3:代码随想录方法: 动态规划-计算删除的思路 速度 2ms
public boolean isSubsequence(String s, String t) {
// 先上代码
char[] tList = t.toCharArray();
char[] sList = s.toCharArray();
int[][] dp = new int[sList.length+1][tList.length+1];
for(int i = 1;i < sList.length + 1;i++){
for(int j = 1;j < tList.length + 1;j++){
if(sList[i-1] == tList[j-1]){
dp[i][j] = dp[i-1][j-1] + 1;
} else{
dp[i][j] = dp[i][j-1];
}
// System.out.print(dp[i][j]);
}
// System.out.println();
}
return dp[sList.length][tList.length] == sList.length;
// 解析:这里看起来和第一种方法求最大公共子序列特别像,实际上确实差不多,只是进行了一定的裁剪,
// 这里实际上就是由于这道题的特殊性,它是求是或否,不需要求具体的公共子序列长度,所以不需要看
// dp[i-1][j],即每个元素单独扫描即可,没遇到,左边复制,遇到,在dp[i-1][j-1]基础上+1,只有
// s是t的子序列,最后dp[sList.length][tList.length]才会与s的长度相等。
// 注:老实说,感觉这个方法有点怪怪的,有点强行这样做的感觉,但看公式其实很好模拟的,可以自己脑袋
// 头模拟一下案例,就会发现是每个单个字符扫描的感觉,也有可能是我没理解透?
}
}