leetCode解题报告之O(n)线性时间求最大子序列和(Maximum Subarray)

题目:

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.

click to show more practice.

分析:

给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大 
例如:整数序列[−2,1,−3,4,−1,2,1,−5,4]的最大子序列[4,−1,2,1] 的和为6,。


解题思路:

1.我们最容易想到的就是暴力法来求解了,我们先来看看两种穷举法的写法和时间复杂度(分别为O(n^3) 和 O(n^2))

2.我会使用分治法来完成这道题目,复杂度为O(nlogn)

3.我会使用DP的思想来做这道题目,复杂度为O(n)


一、穷举法(暴力)【O(n^3)】

public int maxSubArray(int[] A) {
		int len = A.length;
		int max = Integer.MIN_VALUE;
		//把每种情况都遍历出来,取出最大sum的值
		for (int i=0; i<len; ++i){			
			for (int j=i; j<len; ++j){
				int temp = 0;
				for (int k=i; k<j; ++k){
					temp += A[k];
				}
				if (temp > max){
					max = temp;
				}
			}
		}
		return max;
	}

二、穷举法的改进(暴力)【O(n^2)】


public int maxSubArray(int[] A) {
		int len = A.length;
		int max = Integer.MIN_VALUE;
		//把每种情况都遍历出来,取出最大sum的值
		for (int i=0; i<len; ++i){		
			int temp = 0;
			for (int j=i; j<len; ++j){
				temp += A[j];
				if (temp > max)
					max = temp;
			}
		}
		return max;
	}

三、分治法(二分法)【O(nlogn)】(这里要怒喷一下,网上好多人都有一份分治法的代码,都是copy来copy去的,但是却不是正确的,这代码是AC过的才发上来的!)

思路:由于我们知道最大子序列可能存在于A数组的左边,右边,或者一点左边一点右边。

所以我们很容易可以联想到,居然这样我们可以把A数组划分成若干个小的子数组,对子数组求出左边的最大值,和右边的最大值,再求出从中间位置到左边的某个位置的最大值、从中间位置到右边的某个位置的最大值,得到了这四个值之后剩下的我们就可以通过比较得到这个子数组的最大值了。(递归的过程)

public class Solution {
    public int maxSum(int[] A, int left, int right )
	{
	    if( left == right ){
	        return A[left];
	    }
	    int center = (left + right) / 2;
	    int maxLeftSum  = maxSum( A, left, center);
	    int maxRightSum = maxSum( A, center+1, right);
	    
	    
	    int maxLeft = Integer.MIN_VALUE, tempLeft = 0;
	    int maxRight = Integer.MIN_VALUE, tempRight = 0;
	    for (int i=center; i>=left; --i){
	    	tempLeft += A[i];
	    	if (tempLeft > maxLeft){
	    		maxLeft = tempLeft;
	    	}
	    }
	    for (int i=center+1; i<=right; ++i){
	    	tempRight += A[i];
	    	if (tempRight > maxRight){
	    		maxRight = tempRight;
	    	}
	    }
	  
	    int maxCenterSum = maxLeft + maxRight;
	    
	    return maxCenterSum > maxLeftSum ? (maxCenterSum > maxRightSum ? maxCenterSum : maxRightSum) : maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;
	}
	
	public int maxSubArray(int[] A){
		int len = A.length;
		return maxSum(A,0,len-1);
	}
}


四、DP思想解题【O(n)】(这里要怒喷一下,网上好多人都有一份分治法的代码,都是copy来copy去的,但是却不是正确的,这代码是AC过的才发上来的!)

public class Solution {
    public int maxSubArray(int[] A) {
		int len = A.length;
		int max = Integer.MIN_VALUE;
		int temp = Integer.MIN_VALUE;
		
		for (int i=0; i<len; ++i){
		    if (temp < 0)
		        temp = A[i];
		    else{
		        temp += A[i];
		    }
		    if (temp > max){
		        max = temp;
		    }
		}
		
		return max;
	}
}

看到这里了,留个言呗O(∩_∩)O,欢迎提出不足的地方!!



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值