[编程题]区间中的最大值

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

区间中的最小数 * 区间所有数的和最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列 [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;

输出:

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

示例:

输入
3
6 2 1
输出
36

解析:
这题最简单的思路就是视当前我们所在的元素是整个区间中最小的数,在区间中,此元素的左边所有的元素以及右边所有的元素皆大于此元素。

因此,问题转换成:
1、遍历整个数组
2、在遍历时,向左与向右寻找所在元素x第一个比此元素要大的元素L,R
3、此区间的计算值等于x*sum(L+1,R-1),再此寻找最大值

代码实现:

#include <iostream>
#include <numeric>

using namespace std;

//局部变量存在栈区,无法存储这么大数组
int arr[500005];

int main()
{
	int n,max=0;
	cin >> n;
	for(int i=0;i<n;i++)
	{
		cin >> arr[i];
	}
	
	//开始遍历数组
	for(int i=0;i<n;i++)
	{
		int min = arr[i];
		//寻找最左值
		int L = i - 1;
		while (L>=0)
		{
			if(arr[L]>=min)
			{
				L--;
			}
			else
			{
				break;
			}
		}
		//别忘了加1
		L++;

		//寻找最右值
		int R = i + 1;
		while (R<n)
		{
			if (arr[R] >= min)
			{
				R++;
			}
			else
			{
				break;
			}
		}
		//别忘了减1
		R--;

		//求和
		int sum = accumulate(arr+L,arr+R+1, 0);

		//更新最大值
		max = (max > sum * min) ? max : sum * min;
	}
	cout << max;
	return 0;
}

关于accumulate()函数可以参见https://blog.csdn.net/weixin_43919932/article/details/113354255解释

注:
在题目整个遍历过程中,显然我们的时间复杂度是接近n^2的,当n变得很大时,将极具耗时。有一句话说的好,程序员应当像资本家一样去压榨计算机每一份资源,提高自己代码效率(嗯,我说的),这里解释一下大佬的解法。

在题目中,n值是可以达到很大的(1<=n<=500000),但其中一项参数却维持在一个较小的区间且涉及到最大值的比较中,就是每个元素的取值范围(0<=x<=100)。

而在外部循环中,我们实质上的工作就是在确定区间最小值,因此区间N和区间X似乎可以进行替换。

代码:

#include <iostream>

using namespace std;

//局部变量存在栈区,无法存储这么大数组
int arr[500005];

int main()
{
	int n,max=0;
	cin >> n;
	for(int i=0;i<n;i++)
	{
		cin >> arr[i];
	}

	//arr[n]=0是为方便计算最后一节区间的计算值'
	arr[n] = 0;

	//假设有数组X[i],表示在数组arr中,元素都大于i的子区间的题目所需求的最大值,不过在只是求最大值的情况下这个数组可以省略
	for(int j=100;j>=1;j--)
	{
		int sum = 0;//临时存储和
		int min = j;//子区间最小值
		//对数组进行遍历,一次遍历我们可以找出多个区间
		for(int i=0;i<=n;i++)
		{
			//满足条件,则开始分割子区间
			if(arr[i]>=j)
			{
				sum += arr[i];
				min = (min < arr[i]) ? min : arr[i];
			}
			//不满足条件,子区间断开,计算子区间的值并更新最大值,但此时仍继续遍历,寻找下一个满足子区间
			else
			{
				max = (max > sum * min) ? max : sum * min;

				sum = 0;
				min = j;
			}
		}
	}
	cout << max;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值