先赞后看,良好习惯。
光看不赞、双商减半。
题目
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
样例
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
输入:nums = [1]
输出:1
输入:nums = [5,4,-1,7,8]
输出:23
思路一:贪心算法
思路:题目最终要求得最大子序的和,根据贪心算法的思想,则需要在每一轮遍历时,都基于当前元素,通过舍弃或累加求出当前最大和的最优解
。
变量:一共使用四个变量
当前值:
即 当前遍历数组得到的数字。当前和:
分两种情况:
①之前和 小于0时, 当前和 = 当前值。
②之前和 大于0时, 当前和 = 当前和 + 之前和。之前和:
遍历上一个数组元素时的当前和。最大和:
即 当前和 和 上一轮的 最大和 里更大的值。
以这个样例来进行分析 [5,4,-20,7,8]
第一轮 | 第二轮 | 第三轮 | 第四轮 | 第五轮 | |
---|---|---|---|---|---|
当前值 | 5 | 4 | -20 | 7 | 8 |
当前和 | 5 | 5 + 4 = 9 | 9 +(-20) = -11 | (因为-11小于0所以被舍弃)7 | 8 + 7 = 15 |
之前和 | null | 5 | 9 | -11 | 7 |
最大和 | 5 | 9 | 9 | 9 | 15 |
所以最后的结果就是 15
根据思路可以写出代码
class Solution {
public int maxSubArray(int[] nums) {
int max_sum = 0; //最大和
int cur_sum = 0; //当前和
int per_sum = 0; //之前和
for(int i = 0;i<nums.length ;i++){
//初始化赋值
if(i==0){
cur_sum = nums[i];
max_sum = nums[i];
per_sum = cur_sum;
continue;
}
if(per_sum < 0){
cur_sum = nums[i];
}else{
cur_sum = per_sum + nums[i];
}
per_sum = cur_sum;
max_sum = Math.max(cur_sum,max_sum);
}
return max_sum;
}
}
提交结果:(空间复杂度有待优化)
思路二:动态规划算法
变量:一共使用两个个变量
当前值:
即 当前遍历数组得到的数字。动态规划值:
分两种情况:
①上一轮的动态规划值 小于0时, 本轮的动态规划值 = 当前值。
②上一轮的动态规划值 大于0时, 本轮的动态规划值 = 当前值 + 上一轮的动态规划值。
以这个样例来进行分析 [5,4,-20,7,8]
第一轮 | 第二轮 | 第三轮 | 第四轮 | 第五轮 | |
---|---|---|---|---|---|
当前值 | 5 | 4 | -20 | 7 | 8 |
动态规划值 | 5 | 5 + 4 = 9 | 9 + (-20)= -11 | (因为-11小于0被舍弃)7 | 7 + 8 = 15 |
然后找到动态规划的最大值,所以就是 15
根据思路可以写出代码
class Solution {
public int maxSubArray(int[] nums) {
int dp[] = new int[nums.length]; //存放动态规划的值
for( int i = 0 ; i < nums.length ; i++ ){
if( i == 0 ){
//初始化第一个值
dp[i] = nums[i];
continue;
}
if( dp[i-1] < 0){
dp[i] = nums[i];
}else{
dp[i] = dp[i-1] + nums[i];
}
}
Arrays.sort(dp);
return dp[nums.length-1];
}
}
提交结果:(时间复杂度、空间复杂度均有待优化)
小结
通过实践,我们发现,贪心算法和动态规划算法都是典型的”趋利避害“的算法,舍弃对自己不利的,保留有利的。加深了我对于这两种算法的理解。