【实现】最大连续子序列和——第7周《算法》课程提到的 google笔试题/浙大研究生复试机试题

    问题:求取数组中最大连续子序列和,例如给定数组为A={1, 3, -2, 4, -5}, 则最大连续子序列和为6,即1+3+(-2)+ 4 = 6。

    大家在搜索答案之前,先思考10分钟,看自己能够想到几种答案?最佳的解法是O(N)复杂度。


    思考了20分钟,还是只找到笨方法。后来参考了“石锅拌饭“最大连续子序列和”的解释,写下了Java代码。

输入:
        测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K< 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。

样例输入:
6
-2 11 -4 13 -5 -2
10
-10 1 2 3 4 -5 -23 3 7 -21
6
5 -8 3 2 5 0
1
10
3
-1 -5 -2
3
-1 0 -2
0

运行结果

【实现】最大连续子序列和——第7周《算法》课程提到的 google笔试题/浙大研究生复试机试题_第1张图片


源码如下(提示:测试数据以文件testMaxSequence.txt给出,请放在project目录下)

package DP;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

/**
 * 功能:给定数组,计算连续最大子序列和
 * 数据示例:http://www.huangbin.name/archives/68
 * 算法思想:http://blog.csdn.net/sgbfblog/article/details/8032464 
 * @author Administrator
 *
 */
public class MaximumList {

	/**
	 * @param args
	 * @throws FileNotFoundException 
	 */
	public static void main(String[] args) throws FileNotFoundException {
		// TODO Auto-generated method stub
		int num = 0;
		int[] array;
		long sumMax = 0;
		
		Scanner sc = new Scanner(new File("testMaxSequence.txt"));
		if(sc.hasNextInt()){
			num = sc.nextInt();
		}
		while(num>0){
			array = new int[num];
			for(int i=0; i<num; i++){
				array[i] = sc.nextInt();
			}
			//输出数组,并计算最大子序列和
			sumMax = maxSequence(array);
			for(int tmp:array){
				System.out.print(tmp+" ");
			}
			System.out.println();
			System.out.println("最大子序列和 = " + sumMax);
			
			//输出数组,并计算最大子序列和
			long[] result = maxSequence2(array);
			System.out.println("最大子序列起止下标为 [" + result[1] +" " + result[2] +"]");
			for(int i=(int) result[1]; i<=result[2]; i++){
				System.out.print(array[i]+" ");
			}
			System.out.println("\n");
			
			
			//读取下一个测试数据
			if(sc.hasNextInt()){
				num = sc.nextInt();
			}
		}
		
		sc.close();
	}
	
	public static long maxSequence(int[] array){
		//动态规划:假设当前数组下标为i,下标[0,i-1]的序列和为preMax,最大序列和为sumMax
		//则 如果preMax<=0,包括当前下标i的元素后序列和为array[i],否则为 preMax+array[i]
		long sumMax = array[0], preMax = array[0];
		for(int i=1; i<array.length; i++){
			if(preMax<=0){
				preMax = array[i];	//没有必要背上前面的负担
			}else{
				preMax += array[i];  //前面序列为正数,肯定捡上
			}
			
			if(sumMax<preMax){
				sumMax = preMax;
			}
		}
		return sumMax;
	}
	
	//返回子序列最大值 及 子序列起止下标
	public static long[] maxSequence2(int[] array){
		//动态规划:假设当前数组下标为i,下标[0,i-1]的序列和为preMax,最大序列和为sumMax
		//则 如果preMax<=0,包括当前下标i的元素后序列和为array[i],否则为 preMax+array[i]
		long sumMax = array[0], preMax = array[0];
		int end = 0;		//子序列最大值时 数组起止下标
		for(int i=1; i<array.length; i++){
			if(preMax<=0){
				preMax = array[i];	//没有必要背上前面的负担
			}else{
				preMax += array[i];  //前面序列为正数,肯定捡上
			}
			
			if(sumMax<preMax){
				sumMax = preMax;				
				end = i;
			}
		}
		
		long[] result = new long[3];
		result[0] = sumMax;
		result[2] = end;
		//计算开始下标:假设数列为-2 11 -4 13 -5 -2,最大值20,end=3
		//假设开始下标为 k,则一定有 array[k]+array[k+1]+…+array[end]=20,反其道而行之
		while(sumMax-array[end]>0){
			sumMax -= array[end];
			end--;
		}
		result[1] = end;
		
		return result;
	}

}

    知易行难,唯有多实践,才能够真正理解算法思想。勤思考,勤总结,勤实践。


你可能感兴趣的:(java,算法,最大连续子序列和)