53.Maximum Subarray

题目链接:https://leetcode.com/problems/maximum-subarray/description/

题目大意:给出一串数组,找出其最大连续子序列和,例子如下:

法一(超时):时间复杂度o(n^2),两层for循环,记录每一个数值后的连续序列的最大和,里层for循环记录当前数值的连续序列的最大和,如果比最大值大,则记录。

这个方法可以用来解决记录最大序列和的开始和结束下标的问题,即在里层for循环中的当前数值的连续序列的最大和比最大值大时,出现调换时可以在这个步骤中记录开始和结束下标。

代码如下:

 1 int res = Integer.MIN_VALUE;
 2         for(int i = 0; i < nums.length; i++) {
 3             int cnt = 0;
 4             //对于每一个数值,判断其后面的连续子序列和得到最大值
 5             for(int j = i; j < nums.length; j++) {
 6                 cnt += nums[j];
 7                 if(cnt > res) {
 8                     res = cnt;
 9                 }
10             }
11         }
12         return res;
View Code

法二(借鉴):时间复杂度o(n),代码如下(耗时13ms):

 1         //法一
 2 /*        
 3         //这里要把res赋值为最小值,以防序列中负数的出现
 4         int res = Integer.MIN_VALUE;
 5         int sum = 0;
 6         for(int i = 0; i < nums.length; i++) {
 7             if(sum < 0) {
 8                 sum = nums[i];//如果当前值前面的sum<0,则将sum重新赋值为当前值,以此值为新的起点开始计算最大和
 9             }
10             else {
11                 sum += nums[i];//否则, 将当前值加入sum中
12             }
13             if(sum > res) {
14                 res = sum;
15             }
16         }
17         return res;*/
18         //法二
19         //结论:如果a[i]是负的,那么它不可能代表最优序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过a[i+1]作起点而得到改进。类似地,任何负的子序列不可能是最优子序列的前缀
20         //如果在内循环中检测到从a[i]到a[j]的子序列是负的,那么可以推进i到j+1。
21         //在这里的运用也就是当sum<0时,即刻将sum重置为0。
22         //这里一定要把res赋值为最小值,因为序列中会有负数的情况
23         int res = Integer.MIN_VALUE;
24         int sum = 0;
25         for(int i = 0; i < nums.length; i++) {
26             sum += nums[i];//System.out.println(sum);
27             if(sum > res) {
28                 res = sum;
29             }
30             //这里不要用else,因为类似序列{-2,-1}这种就计算不到最后的解
31             if(sum < 0) {//如果sum<0,则将sum重置,也就是发现sum<0,则说明此序列不会是最大和序列
32                 sum = 0;
33             }
34         }
35         return res;
View Code

法三(借鉴):分治,时间复杂度o(nlogn),参考http://blog.csdn.net/silangquan/article/details/8062229, 代码如下(耗时18ms):

 1     public int maxSubArray(int[] nums) {
 2         return solution(nums, 0, nums.length - 1);
 3     }
 4     
 5     public int solution(int[] a, int left, int right) {
 6         //处理left==right中间值情况
 7         if(left == right) {
 8             return a[left];
 9         }
10         
11         int mid = (left + right) / 2;
12         //递归求左边最大和
13         int maxLeft = solution(a, left, mid);
14         //递归求右边最大和
15         int maxRight = solution(a, mid + 1, right);
16         
17         //当前数组左边包含最后一个数的最大和
18         int maxLeftSum = Integer.MIN_VALUE;
19         int leftSum = 0;
20         for(int i = mid; i >= left; i--) {
21             leftSum += a[i];
22             if(maxLeftSum < leftSum) {
23                 maxLeftSum = leftSum;
24             }
25         }
26         
27         //当前数组右边包含第一个数的最大和
28         int maxRightSum = Integer.MIN_VALUE;
29         int rightSum = 0;
30         for(int i = mid + 1; i <= right; i++) {
31             rightSum += a[i];
32             if(maxRightSum < rightSum) {
33                 maxRightSum = rightSum;
34             }
35         }
36         
37         //左边最大和,右边最大和,包含左右两边的最大和,返回这三个值中的最大值
38         int tmp = maxLeft > maxRight ? maxLeft : maxRight;
39         return tmp > (maxLeftSum + maxRightSum) ? tmp : (maxLeftSum + maxRightSum);
40     }
View Code

 

posted on 2017-10-23 21:07  二十年后20  阅读(154)  评论(0编辑  收藏  举报

导航