1. 题目描述
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
2. 解题思路
核心点是:dpi作为以数组中第 i 个元素结尾的子数组的最大和。那么就有以下关系:
3. 代码
public class ques42 {
private List<Integer> ans = new LinkedList<>();
public int maxSubArray(int[] nums) {
int len = nums.length - 1;
recur(len, nums);
int result = ans.get(0);
for (int i = 1; i < ans.size(); i++) {
if(ans.get(i) > result)
result = ans.get(i);
}
return result;
}
public int recur(int i, int[] nums){
if(i==0) {
ans.add(nums[0]);
return nums[0];
}
int tmp = recur(i-1, nums);
if(tmp <= 0){
int maxi = nums[i];
ans.add(maxi);
return maxi;
}else {
int maxi = tmp + nums[i];
ans.add(maxi);
return maxi;
}
}
//方法2:与我思路相同,但空间复杂度为o(1),我的为o(n)
//时间复杂度也更低,可能我需要再遍历一次ans
public int maxSubArray2(int[] nums) {
int max = nums[0];
int former = 0; //用于记录dp[i-1]的值,对于dp[0]而言,其前面的dp[-1]=0
int cur = nums[0]; //用于记录dp[i]的值
for(int num:nums){
cur = num;
if(former>0) cur +=former;
if(cur>max) max = cur;
former = cur;
}
return max;
}
}
4. 遇到的坑
在我使用递归求解时,原本的写法为:
public int recur(int i, int[] nums){
if(i==0) {
ans.add(nums[0]);
return nums[0];
}
if (recur(i-1, nums) <= 0){
int maxi = nums[i];
ans.add(maxi);
return maxi;
}else {
int maxi = recur(i-1, nums) + nums[i];
ans.add(maxi);
return maxi;
}
}
这里在 if 和 else 中,都执行了递归,因此add()调用了多次。例如:
① 当 i = 5 时,先执行 if 中的recur(4),这时由于会递归到recur(0),因此在此过程中ans.add()会被一直调用;
② 计算结束,发现 if 不成立。进入到else中时,又会去递归到recur(0),这就多重复了一次。
因此需要将 recur(i-1, nums)存储为一个临时变量,放在 if 外面,保证其在一次recur()中,只执行一次。如:
public int recur(int i, int[] nums){
if(i==0) {
ans.add(nums[0]);
return nums[0];
}
int tmp = recur(i-1, nums);
if(tmp <= 0){
int maxi = nums[i];
ans.add(maxi);
return maxi;
}else {
int maxi = tmp + nums[i];
ans.add(maxi);
return maxi;
}
}