给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中[区间的最小数 * 区间所有数的和]最大

给定一个数组,要求选择一个区间,使区间内最小数乘以区间内所有数之和达到最大。对于序列[6, 2, 1],最大计算值区间为[6],计算值为36。问题在于解决此问题时出现Java堆空间内存溢出错误,通过优化算法降低内存使用,但仅有70%的测试用例通过。解决方案是按y轴升序、x轴降序排序,比较并更新最大元素。" 53229483,1432347,Sprint规划会议:理解与决策,"['敏捷开发', 'Scrum框架', '产品管理', '团队协作', '项目规划']

给定一个数组序列, 需要求选出一个区间, 使得该区间是所有区间中经过如下计算的值最大的一个:

区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列  [6 2 1]则根据上述公式, 可得到所有可以选定各个区间的计算值:

 

[6] = 6 * 6 = 36;

[2] = 2 * 2 = 4;

[1] = 1 * 1 = 1;

[6,2] = 2 * 8 = 16;

[2,1] = 1 * 3 = 3;

[6, 2, 1] = 1 * 9 = 9;

 

从上述计算可见选定区间 [6] ,计算值为 36, 则程序输出为 36。

区间内的所有数字都在[0, 100]的范围内;


输入描述:
第一行输入数组序列长度n,第二行输入数组序列。
对于 50%的数据,  1 <= n <= 10000;
对于 100%的数据, 1 <= n <= 500000;


输出描述:
输出数组经过计算后的最大值。

输入例子1:
3
6 2 1

输出例子1:
36

解题思路:

对于序列a中开始于i结束于j的区间最小值*区间所有数和 = dpmin[i][j] * dpsum[i][j];

对于dpmin[i][j]:开始于i结束于j的区间最小值



对于dpsum[i][j]:开始于i结束于j的区间最小值



实现思路

创建2个int[a.length][a.length]的矩阵,分别计算dpmin[i][j],dpsum[i][j],然后遍历求积最大;

但是报错:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

(Java堆空间内存溢出)

为减小内存:只用dpminLast、dpminNow记录和更新dpmin

                            dpsumLast 、dpsumNow记录和更新dpsum

代码实现

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int len = in.nextInt();
		int[] a = new int[len];
		for (int i = 0; i < a.length; i++) 
			a[i] = in.nextInt();
		
//		int[][]  dpmin = new int[len][len];
		int dpminLast = a[0],dpminNow = a[0];
		int dpsumLast = a[0],dpsumNow = a[0];
		int temp = dpminNow*dpsumNow;
		for (int i = 0; i < a.length; i++) {
			dpminLast = a[i];
			dpsumLast = a[i];
			if(temp < a[i]*a[i])
				temp = a[i]*a[i];
			for (int j = i + 1 ; j < a.length; j++) {
				dpminNow = a[j] < dpminLast ? a[j] : dpminLast;
				dpsumNow = a[j] + dpsumLast;
				if(temp < dpminNow*dpsumNow)
					temp = dpminNow*dpsumNow;
				dpminLast = dpminNow;
				dpsumLast = dpsumNow;
			}
		}
		
//		for (int i = 0; i < a.length; i++) { 
//			dpmin[i][i] = a[i];
//			for (int j = i + 1; j < a.length; j++) {
//				dpmin[i][j] = a[j] < dpmin[i][j-1] ? a[j] : dpmin[i][j-1];
//			}
//		}
//		
//		int[][]  dpsum = new int[len][len];
//		for (int i = 0; i < a.length; i++) { 
//			dpsum[i][i] = a[i];
//			for (int j = i + 1; j < a.length; j++) {
//				dpsum[i][j] = a[j] + dpsum[i][j-1];
//			}
//		}
//		int temp = dpmin[0][0]*dpsum[0][0];
//		for (int i = 0; i < a.length; i++) 
//			for (int j = i; j < a.length; j++) 
//				if(temp < dpmin[i][j]*dpsum[i][j])
//					temp = dpmin[i][j]*dpsum[i][j];
		
		System.out.println(temp);
	}
}


但是只有70%的通过率!!!

本题能正确通过的思路是:按照y轴升序,x轴降序排序,然后从最后一个元素开始,始终与(y后者x)最大元素做对比,如果比最大元素大,就保存到栈中,然后把最大元素更新;如果小于最大元素,那么就查看下一个元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值