码迷,mamicode.com
首页 > 编程语言 > 详细

Java实现:求子数组的最大和(数组)

时间:2015-02-01 12:09:43      阅读:1190      评论:0      收藏:0      [点我收藏+]

标签:java   算法   

求子数组的最大和(数组)

题目:
输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为
O(n)

例如输入的数组为 1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为 3, 10, -4, 7, 2,因此输出为该子数组的和 18。 


解题思路:

我觉得用户关心的的数据有两个,一个是子数组的和,还有一个是子数组具体有哪些元素,所以我们可以封装一个子数组类SubArray,成员有子数据开始索引,结束索引,以及子数组和。

对于此题,我看其他博客解答时传入了一个子数组长度size的入参,求的所有长度为size的子数组的最大值。但是上面看题目中,没有任何关于该size入参的说明。我们还是提供这两种方法的解题方法。

第一种,传入指定数组长度size。这种方法实现比较简单。首先我们有一个最大子数组SubArray的变量maxArray,然后我们再初始化一个大小为size的SubArray对象,命名为currentArray。当我们遍历用户元素时,先从currentArray中移除第一个元素,再放入用户元素,当新的currentArray的和大于maxArray时,更新maxArray即可。

第二种,没有传入数组长度size。我们只要确保索引index之前的数据之和加上index索引数据>0,那么index索引对应最大值是有贡献的。当index之前的数据之和加上index索引之和<0,则表示index之前的数据(包括index)都是无用的,删除即可。当得到得到上面数组时,我们需要反序循环一次,将队尾的负值移除,确保子数组的和是最大。

代码如下:

public class MaxSubArray {
	
	private List<Integer> valueList = null;
	
	public MaxSubArray(){
		valueList = new ArrayList<Integer>();
	}
	
	public MaxSubArray(int size){
		valueList = new ArrayList<Integer>(size);
	}
	
	public void add(int value){
		valueList.add(value);
	}
	
	public SubArray maxSubArray(int size){
		if (valueList.isEmpty()){
			return null;
		}
		// 初始化当前操作的数组和最大数组
		int currentSize = Math.min(valueList.size(), size);
		SubArray currentArray = new SubArray(0, 0, 0);
		for (int i = 0; i < currentSize; i++){
			currentArray.endIx = i;
			currentArray.sum += valueList.get(i);
		}
		SubArray maxArray = new SubArray(currentArray);
		
		// 计算
		for (int i = size; i < valueList.size(); i++){
			// 如果当前数组没有预留一个空位,则从头移除元素,保证预留一个空位
			if (currentArray.endIx - currentArray.startIx + 1 >= size){
				currentArray.sum -= valueList.get(currentArray.startIx);
				currentArray.startIx++;
			}
			currentArray.endIx = i;
			currentArray.sum += valueList.get(i);
			if (currentArray.sum > maxArray.sum){
				maxArray.copy(currentArray);
			}
		}
		return maxArray;
	}
	
	public SubArray maxSubArray(){
		if (valueList.isEmpty()){
			return null;
		}
		// 从前往后循环,只要第i位置之前的总和是小于第i位置值,则包括第i位置的子数组丢弃。
		SubArray lastMaxArray = new SubArray(0, 0, valueList.get(0));
		SubArray resultArray = new SubArray(lastMaxArray);
		for (int i = 1; i < valueList.size(); i++){
			int value = valueList.get(i);
			if (resultArray == null){
				resultArray = new SubArray(i, i, value);
				continue;
			}
			if (resultArray.sum + value < 0){
				if (resultArray.sum > lastMaxArray.sum){
					lastMaxArray.copy(resultArray);
				}
				resultArray = null;
				continue;
			}
			resultArray.endIx=i;
			resultArray.sum += valueList.get(i);
		}
		// 从后向前循环,只要第i位置之后的总和是小于第i位置值,则包括第i位置在内的之后数组丢弃。
		for (int i = resultArray.endIx; i >= resultArray.startIx; i--){
			int value = valueList.get(i);
			if (value < 0){
				resultArray.endIx = i - 1;
				resultArray.sum -= value;
				continue;
			} else {
				break;
			}
		}
		return resultArray;
	}
	
	public class SubArray{
		private int startIx;
		private int endIx;
		private long sum;
		public SubArray(SubArray copy){
			copy(copy);
		}
		public SubArray(int startIx, int endIx, long sum){
			this.startIx = startIx;
			this.endIx = endIx;
			this.sum = sum;
		}
		public void copy(SubArray copy){
			this.startIx = copy.startIx;
			this.endIx = copy.endIx;
			this.sum = copy.sum;
		}
		public int getStartIx(){
			return this.startIx;
		}
		public int getEndIx(){
			return this.endIx;
		}
		public long getSum(){
			return this.sum;
		}
	}
}

先去吃饭,等会来写Junit测试。


Java实现:求子数组的最大和(数组)

标签:java   算法   

原文地址:http://blog.csdn.net/fangchao2061/article/details/43370445

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!