问题说明
* 有 n 个学生站成一排,每个学生有一个能力值,
* 牛牛想从这 n 个学生中按照顺序选取 k 名学生,
* 要求相邻两个学生的位置编号的差不超过 d,
* 使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
为了方便理解,我们假设每个学生的能力值都是正数
-
一共有n个学生,我们用正整数数组arr[n]表示
-
需要在n个学生中找到k个人的问题其实可以理解为:
- 已经找到了最后一个人的位置
- 再找到前面k-1个人的位置即可
-
不妨用一个select[k][n]数组表示
- select[i][j]:表示一共选择了i+1个人,且最后一人位置在j时的乘积
-
那么select[i][j]该怎么表示呢?
- 我们可以知道select[0][0] ~ select[0][n-1]表示只选择一个人且这个人位置在任意时的乘积,
select[0][0]的值是等于arr[0]的,同理select[0][j]=arr[j]- 也就是当我们画出select数组时,select[0]这一行的所有数据都可以确定
我们假设arr={5,2,3,8,1},n=5,k=3,d=2
2. 再来看第二行,select[1][0]表示选择了2个学生,最后一个位置为第0号,显然不可能,select[1][0]的值没有意义,同理 第i行前i个数据都无意义
3. 那么其余数怎么确定呢? - 举个例子,select[1][1]表示选择2个人,第二个人在1号位置
那么只可能一种情况,0号位置和1号位置都被选择了,那么select[1][1]=arr[1]*select[0][0] - 那么如果是select[1][2]的值如何确定?
selec[1][2]表示选择2个人,最后一个人位置在第2号位置上
它的值是依赖于除最后人外前面所有人的位置,即依赖于:select[0]这一行
最后一人在第2号位置上,那么它前面一人就会落在【2-d,2-1】位置间,即:select[0][0]到select[0][1]这个区间,
在这个区间内前一个人都可以落脚。
找到这个区间内使得select[0](前一个人落脚)最大值,再乘以arr[j]得出select[1][2]的值
- 也就是当我们画出select数组时,select[0]这一行的所有数据都可以确定
- 所以具体确定select数组的值代码为
- 我们可以知道select[0][0] ~ select[0][n-1]表示只选择一个人且这个人位置在任意时的乘积,
`//从select[1]到select[k-1]
for(int i=1;i<k;i++){
//第一个有值的地方开始,计算
for(int j=i;j<n;j++){
//select[1][1]=max(select[1-1][1-1],..,select[1-1][1-d])*arr[1]
//不能越界,选择select[i-1]中的最大值
int max=0;
for(int t=j-1;t>=Math.max(0,j-d);t--){
if(select[i-1][t]>max)
max=select[i-1][t];
}
select[i][j]=max*arr[j];
}
}`
* 最后在select数组最后一行select[k-1]行中找到最大值即可