剑指offer42:连续子数组的最大和

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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值