DP习题:hdu 1003 Max Sum

原题目见:hdu 1003 Max Sum

Problem Description

Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.


Input

The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).

Sample Input

2

5 6 -1 5 4 -7

7 0 6 -1 1 -6 7 -5

Sample Output

Case 1:
14 1 4
Case 2:
7 1 6

 

题目分析:

给一列数字,求出数组中和最大的连续子数组。

1、求出当前数组中每个位置(作为子数组结尾)对应的最大子数组和;

由于是连续子数组,所以每个位置的连续子数组最大值只需要判断相对于前一个数字的最大子数组即可;如果把当前数值连上上一个数值对应的字符串作为尾位后,数字大于其本身,则有加入数组的意义;否,则另开一个子数组。

例如:[-1,5,4,-10,2,9],

5对应[-1]这个子数组值(和为-1),加入后[-1,5]求和得4,不如自己作为新的子数组[5];

2对于前一个数值-10对应得最大和子数组[5,4,-10](和为-1),加入后[5,4,-10,2]求和得(-1+2=)1<2,则另开一过子串;

最终得到dp数组:[-1,5,9,-1,2,11]

对应记录的连续符:[1,0,1,1,0,1](连续为1,新开为0)

2、最终检索dp得到最大子数组和及对应位置,向前检索连续符记录数组即可以得到开始位置;

代码实现如下

import java.util.Scanner;

public class hdu1003MaxSum {
	
	public static void main(String[] args) {
//		int[] arr = new int[] {-1,5,4,-10,2,9};
//		int[] arr = new int[] {0,6,-1,1,-6,7,-5};
		
//		int[] arr1 = {6,-1,5,4,-7};
//		solve(arr);
		Scanner scan = new Scanner(System.in);
		int t = scan.nextInt();
		while(t-- != 0) {
			int m = scan.nextInt();
			int[] arr = new int[m];
			for(int i = 0;i<m;i++)
				arr[i] = scan.nextInt();
			solve(arr);
		}
	}
	
	
	
	//求解
	public static void solve(int[] arr) {
		
		int[][] dp = new int[2][arr.length];
		dp[0][0]= arr[0];dp[1][0]= 0;
		
		//dp[0][i]:当前位置之前的子串最大值
		//如果i位置的arr[i]加上i-1位置的dp[0][i-1]反而变小了,就等于其本身
		//如果是加上前一个值得到的dp,则记为1;否则记为0(designed for exception like [-1,5,4,-10,2,9])
		for(int i=1;i<arr.length;i++) {
			if(dp[0][i-1]+arr[i]<arr[i]) {
				dp[0][i] = arr[i];
				dp[1][i] = 0;
			}
			else {
				dp[0][i] = dp[0][i-1]+arr[i];
				dp[1][i] = 1;
			}
		}
		//找出最大值位置及其对应的子串的首部
		int i = maxIndex(dp[0]);
		for(;i>=0;i--) {
			if(dp[1][i] == 0)
				break;
		}
		//根据题意,补充首部前的0
	//	while(i-1>0&&arr[i-1]==0)
	//		i=i-1; 
	//	
	//	
		System.out.println(dp[0][maxIndex(dp[0])] + " " + (i+1) + " " + (maxIndex(dp[0])+1));
	}
	//求dp(第一次出现的)最大值的索引
	public static int maxIndex(int[] arr) {
		int m = 0;
		for(int i=0;i<arr.length;i++)
			if(arr[i]>arr[m])
				m=i;
		return m;
	}

}

其实还有种做法是在分别检索start和stop,伪代码如下:

for start = 0 : length(arr)
    for stop =start : length(arr)
        //计算并判断start到stop之间的数据的和是否为最大值,不断更新最大值;
    end
end

这种算法的时间复杂度为O(n²),使用动态规划的方式时间复杂度为O(n)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值