Leetcode-贪心/动态规划/分治法-53. 最大子序和

题目:

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

示例:

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

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


题解:

这道题算是经典了,可以用多种方法解答

我用的就是贪心,

用两个指标nows和max来保存当前和以及目前最大值

从左到右遍历求和,若和大于0,则计入nows,更新max

否则抛弃当前所有值,重新记录nows

 

代码:

class Solution {
   public int maxSubArray(int[] nums) {
    int len = nums.length, max, nows;
    if (len == 0) return 0;
    // 要尽量大,就尽量不要负数
    nows = max = nums[0];
    for (int i = 1; i < len; i++) {
        if (nows > 0) nows += nums[i]; // 之前的和 > 0,那就累计进来
        else nows = nums[i]; // 之前的和 <= 0,那就重新开始
        if (nows > max) max = nows; // max = Math.max(max, nows);
    }
    return max;
   }
}

 

其他:

还有动态规划方法:即从左到右依次遍历更新数组值为前面数字的和(在加上大于其本身情况下),然后取数组中最大数即为答案

class Solution
{
public:
    int maxSubArray(vector &nums)
    {
        //类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
        int result = INT_MIN;
        int numsSize = int(nums.size());
        //因为只需要知道dp的前一项,我们用int代替一维数组
        int dp(nums[0]);
        result = dp;
        for (int i = 1; i < numsSize; i++)
        {
            dp = max(dp + nums[i], nums[i]);
            result = max(result, dp);
        }

        return result;
    }
};

分治法:以数组中心为分界线,左右分别用贪心/动态规划求解(python)

    public int maxSubArray(int[] nums) {
        return maxSubArrayDivideWithBorder(nums, 0, nums.length-1);
    }

    private int maxSubArrayDivideWithBorder(int[] nums, int start, int end) {
        if (start == end) {
            // 只有一个元素,也就是递归的结束情况
            return nums[start];
        }

        // 计算中间值
        int center = (start + end) / 2;
        int leftMax = maxSubArrayDivideWithBorder(nums, start, center); // 计算左侧子序列最大值
        int rightMax = maxSubArrayDivideWithBorder(nums, center + 1, end); // 计算右侧子序列最大值

        // 下面计算横跨两个子序列的最大值

        // 计算包含左侧子序列最后一个元素的子序列最大值
        int leftCrossMax = Integer.MIN_VALUE; // 初始化一个值
        int leftCrossSum = 0;
        for (int i = center ; i >= start ; i --) {
            leftCrossSum += nums[i];
            leftCrossMax = Math.max(leftCrossSum, leftCrossMax);
        }

        // 计算包含右侧子序列最后一个元素的子序列最大值
        int rightCrossMax = nums[center+1];
        int rightCrossSum = 0;
        for (int i = center + 1; i <= end ; i ++) {
            rightCrossSum += nums[i];
            rightCrossMax = Math.max(rightCrossSum, rightCrossMax);
        }

        // 计算跨中心的子序列的最大值
        int crossMax = leftCrossMax + rightCrossMax;

        // 比较三者,返回最大值
        return Math.max(crossMax, Math.max(leftMax, rightMax));
    }



具体思路的话再看看这个

你可能感兴趣的:(#,LeetCode)