【Leetcode】最大子序和

1、题目
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

这是Leetcode上tag为easy的题,也是一道很经典的题,这里提供两种方法去解决它。
动态规划法:
       我们知道:当加上一个正数的时候,和会增加,当我们加上一个负数时,和会减少。对于最大子序和问题,如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。

class Maximum_Subarray_Solution {
    /***
     * 扫描法:(动态规划)
     * 当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。
     * 如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,
     * 不然的话这个负数将会减少接下来的和。
     * @param nums
     * @return 最大子序和
     */
    public int maxSubArray(int[] nums) {
        int sum = nums[0];
        int num = nums[0];
        int len = nums.length;
        for (int i = 1; i < len; i++) {
            if (sum > 0) {
                sum += nums[i];
            }else {
                sum = nums[i];
            }
            num = Math.max(num,sum);
        }
        return num;
    }
}

进阶

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

这里用分治法实现的代码,时间复杂度为O(nlogn)

class Maximum_Subarray2_Solution {
    /**
     * 采用分治法去求最大子序串
     * 数组从中间分开,最大子序串要么在左边,要么在右边,或者左右都有。
     * 在左和在右用递归,在子序串左右都有的情况,分别求最大,在求和。
     * @param nums
     * @return 最大子序串
     */
    public int maxSubArray(int[] nums,int from,int to) {
        if (from == to) return nums[from]; //分治递归要注意出口条件
        int middle = (from + to) / 2;
        int m1 = maxSubArray(nums,from,middle);//要有递归信任,不要纠结层层深入
        int m2 = maxSubArray(nums,middle + 1,to);

        //针对子序串在两边的情况
        int left = nums[middle];
        int now = nums[middle];
        for (int i = middle - 1; i >= from; --i) {
            now += nums[i];
            left = Math.max(now,left);
        }
        int right = nums[middle+1];
        now  = nums[middle+1];
        for (int i = middle + 2; i <= to; ++i) {
            now += nums[i];
            right = Math.max(now,right);
        }
        int m3 = left + right;
        return max(m1,m2,m3);
    }

    public int max(int a, int b, int c) {
        int ret = 0;
        if (a > b) {
            ret = a;
        } else if (a <= b) {
            ret = b;
        }
        if (ret >= c)
            return ret;
        else
            return c;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值