个人记录-LeetCode 53. Maximum Subarray

来源:互联网 发布:php中单双引号的区别 编辑:程序博客网 时间:2024/06/02 17:00

问题:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [-2,1,-3,4,-1,2,1,-5,4],
the contiguous subarray [4,-1,2,1] has the largest sum = 6.

More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

问题要求:找到连续的字串能得到的最大和。
如果找到O(N)解法后,试着也使用分治方法解决。

代码示例:

1、普通的O(N)算法
分析可得出如下结论:
1 最大和对应的字串,一定从一个正数开始(负数对和没有任何增益)。
-1 2 3的和,一定小于2 3

2 连续子串中间可以有负数,但负数之前的正数和一定要大于该负数。
1 2 -1 3的和,大于任何单独子串的和。

按照该分析可以写出如下代码:

public class Solution {    public int maxSubArray(int[] nums) {        int max = nums[0];        int sum = 0;        for (int i = 0; i < nums.length; ++i) {            sum += nums[i];            //记录每次的最大值            if (sum > max) {                max = sum;            }            //当前连续的子串和为负值,不会有任何增益,舍弃            if (sum < 0) {                sum = 0;            }        }        return max;    }}

2、分治
分治的思想是将一个大问题,转换为若干个小问题。
对于这个题目,一种可行的思路是:
1 选出数组的中间项,那么最终结果对应的子串,可能包含中间项,也可能不包含中间项。
2.1 如果最终结果对应的子串,不包含中间项,那么可以继续对中间项左边的子串、及右边的子串使用分治算法
2.2 如果最终结果对应的子串,包含中间项,那么最终的结果等于从中间项开始,以左、以右连续最大子串的和。
3 真正的结果,等于以上3种结果的最大值。

按照该分析可以写出如下代码:

public class Solution {    public int maxSubArray(int[] nums) {        //divide and conquer        return maxSubArrayDC(nums, 0, nums.length-1);    }    private int maxSubArrayDC(int[] nums, int begin, int end) {        if (begin == end) {            return nums[begin];        }        int middle = (begin + end) / 2;        //不包含中间项,计算左边子串的结果        int leftMax = maxSubArrayDC(nums, begin, middle);        //不包含中间项,计算右边子串的结果        int rightMax = maxSubArrayDC(nums, middle+1, end);        //包含中间项的连续子串        int leftSum = nums[middle];        int tmp = nums[middle];        //左边的最大值        for (int i = middle - 1; i >= begin; --i) {            tmp += nums[i];            if (tmp > leftSum) {                leftSum = tmp;            }        }        //右边的最大值        int rightSum = nums[middle+1];        tmp = nums[middle+1];        for (int i = middle + 2; i <= end; ++i) {            tmp += nums[i];            if (tmp > rightSum) {                rightSum = tmp;            }        }        //最大值即为结果        return Integer.max((leftSum+rightSum), Integer.max(leftMax, rightMax));    }}
0 0
原创粉丝点击