python数组区间_今日头条编程题——给定一个数组序列,需要求选出一个区间,使得该区间是所有区间中“区间中的最小数 * 区间所有数的和”的值最大的一个...

题目描述

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

区间中的最小数 * 区间所有数的和

最后程序输出经过计算后的最大值即可,不需要输出具体的区间。如给定序列 [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]的范围内;

输入描述:

第一行输入数组序列个数,第二行输入数组序列。

输出描述:

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

输入例子

3

6 2 1

输出例子

36

第一次思考

我就看到这个给的输入输出例子,心想这最大值不是可明显的嘛。就是这个数组的最大值的平方,与数组中的最小值再与数组所有元素和,这两者再取个最大值就行了噻。虽然心里想着头条的题怎么可能这么简单,但还是大胆地去提交了代码(python3.5):

def max_region(arr):

max1 = max(arr) * max(arr)

max2 = min(arr) * sum(arr)

print(max(max1, max2, min(arr)*sum(arr)))

if __name__ == '__main__':

n = int(input())

arr = [int(i) for i in input().split()]

max_region(arr)

嘿,你看这个通过率还有75%呢,我还挺高兴的

好孩子怎么能不追求100%的正确率呢?于是我想了想这个显示的错误案例。明显我程序的输出9025,即是数组中最大值95的平方。数组中最小值 与 数组所有元素之和 的乘积,确实是小于9025的。所以,25818是怎么个结果呢?

第二次思考

让我们再来认真地从头到尾看一遍题。

“ 要求选出一个区间,使得该区间是所有区间中经过如下计算的值最大的一个:区间中的最小数*区间所有数的和 ”

看清楚了吧?所以给的案例中为什么:[6] = 6 * 6 = 36 ?这不是指的数组最大值的平方,而是选取了原数组中[6]这个区间,这个区间只有一个数,所以该区间的最小数、以及区间所有数的和都是它本身,所以这个区间返回的值是36。

那么对于原数组来说,取的所有单个值的区间,肯定是最大值对应的那个单值区间乘积最大,这还是没错的。同样,对于原数组来说,取其最小值,和所有值的和,的乘积,是这个数组中最长区间的最大值,这也是没有错的。

然而,对于其他多个数组合的区间,可就不一定了。

举个例子:[24 3 44 76 83],原数组整个区间的 “区间中的最小数 * 区间所有数的和”= 3 * (24+3+44+76+83)= 690,而实际上它的子区间[44 76 83]对应的 “区间中的最小数 * 区间所有数的和” = 44 * (44+76+83)= 8932。谁大谁小就不用多说了哈 ~

所以说,我们得去遍历可能的区间,比较究竟哪个 “区间中的最小数 * 区间所有数的和”才是真正的最大值。如果这个区间包含数组中的最小值,那肯定是整个区间的结果最大;如果这个区间的最小值比整个数组的最小值要大,那就得比较到底哪个区间会得到真正的最大值。

用递归来可以试一试。

首先获得原数组整个区间中的最小值;

计算原数组整个区间的和 与 其最小值 的乘积;

比较这个乘积是否大于当前的最大值,如果是,就需要更新;

将原数组,按照整个区间最小值对应的索引,分割成两个区间,对这两个区间,回到步骤1进行递归调用

按照这个思路的代码(python3.5)如下:

maxs = 0

def max_region(arr):

global maxs

if not arr: # 递归的结束条件

return maxs

max1 = min(arr) * sum(arr)

maxs = max(max1, maxs)

min_index = arr.index(min(arr))

# 包含min(arr)的区间,一定是整个区间中的计算结果最大,则以min(arr)对应的索引分割原数组,对得到的左右两个区间分别递归比较

return max(max_region(arr[0:min_index]), max_region(arr[min_index+1:]), maxs)

if __name__ == '__main__':

n = int(input())

arr = [int(i) for i in input().split()]

print(max_region(arr))

结果显示结果如下:

第三次思考

我们知道,一般递归会有很多重复计算,转成动态规划的话会得到优化。这道题用动态规划如何做?

这位大佬https://blog.csdn.net/alixia111/article/details/80455950的博客写出了Java的动态规划解法,但是最终通过率也只是70%。按照大佬的思路,我们需要定义2个 int[arr.length][arr.length] 的矩阵,分别计算dp_min[i][j],dp_sum[i][j]。dp_min[i][j]表示开始于 i 结束于 j 的区间最小值,dp_sum[i][j]表示开始于 i 结束于 j 的区间所有数之和。

对于序列arr中开始于i,结束于j的 区间中的最小数 * 区间所有数的和= dpmin[i][j] * dpsum[i][j],然后遍历求积最大即可。

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

这……都是个啥……

第四次思考-放弃思考

拜服牛客各大佬们 https://www.nowcoder.com/questionTerminal/e6e57ef2771541dfa2f1720e50bebc9a

LeetCode84. Largest Rectangle in Histogram 题目的变种。

主要思路是以每个数作为最小值,找到它的左边界和右边界,然后最小值乘以边界的累加和;如果是遍历每个值找其左右边界,会超时(应该只能ac70%左右);使用压栈的方法可以使得递增的序列不用重复计算其左右边界(最终用时136ms)。

分享一个看起来比较简单的、可以完全通过的C++代码(大佬写的,待我再好好想一下……):

#include #include #include using namespace std;

int main()

{

int n;

while(cin >> n)

{

int a[n];

for(int i=1; i<=n; i++)

{

cin >> a[i];

}

int Max1 = 0;

for(int i=1; i<=n; i++)

{

int Min1 = a[i];

int sum = a[i];

for(int j=i-1; j>=1; j--)

{

if(a[j] >= Min1)

{

sum += a[j];

}

else break;

}

for(int j=i+1; j<=n; j++)

{

if(a[j] >= Min1)

{

sum += a[j];

}

else break;

}

Max1 = max(Max1, sum*Min1);

}

cout << Max1 << endl;

}

return 0;

}

我枯了……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值