1.暴力
class Solution {
public int maxSubArray(int[] nums) {
// 初始化最大值
int max = Integer.MIN_VALUE;
for(int i = 0; i < nums.length; i++){
int sum = 0;
for(int j = i; j < nums.length; j++){
sum += nums[j];
if(sum > max){
max = sum;
}
}
}
return max;
}
}
注意:这种方式当 i = n - 1时, j = n,内层循环不会执行。
for(int i = 0; i < nums.length; i++){
int sum = nums[i];
for(int j = i + 1; j < nums.length; j++){
sum += nums[j];
if(sum > max){
max = sum;
}
}
}
2.动态规划,dp[i] 表示以 nums[i] 结尾的最大子数组的和
思路:从前向后当前的保存数列开始,只要总值小于0那么就舍弃,因为那一部分值无论存在于哪一个子序列中,都是会让总和变小的。
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]) 有两种情况,一种是加上num[i]的和使目标值变大了此时取 dp[i - 1] + nums[i],二是num[i]本身就比dp[i - 1] + nums[i] 更大,此时取nums[i]
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
dp[0] = nums[0];
int max = nums[0];
for(int i = 1; i < n; i++){
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
max = Math.max(max, dp[i]);
}
return max;
}
}
3.动态规划优化----滚动数组
public int maxSubArray(int[] nums) {
int n = nums.length;
int prev = nums[0], max = nums[0];
for (int i = 1; i < n; i++) {
prev = Math.max(prev + nums[i], nums[i]);
max = Math.max(max, prev);
}
return max;
}
只要总值小于0那么就舍弃,因为那一部分值无论存在于哪一个子序列中,都是会让总和变小的。
如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字
如果 sum <= 0,则说明 sum 对结果无增益效果,需要舍弃,则 sum 直接更新为当前遍历数字
每次比较 sum 和 ans的大小,将最大值置为ans,遍历结束返回结果
class Solution {
public int maxSubArray(int[] nums) {
int ans = nums[0];
int sum = 0;
for(int num: nums) {
if(sum > 0) {
sum += num;
//只要总值小于0就舍弃
} else {
sum = num;
}
ans = Math.max(ans, sum);
}
return ans;
}
}