持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
一、题目描述:
1646. 获取生成数组中的最大值 - 力扣(LeetCode)
给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums :
- nums[0] = 0
- nums[1] = 1
- 当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i]
- 当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1] 返回生成数组 nums 中的 最大 值。
示例 1:
输入:n = 7
输出:3
解释:根据规则:
nums[0] = 0
nums[1] = 1
nums[(1 * 2) = 2] = nums[1] = 1
nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2
nums[(2 * 2) = 4] = nums[2] = 1
nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3
nums[(3 * 2) = 6] = nums[3] = 2
nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3
因此,nums = [0,1,1,2,1,3,2,3],最大值 3
示例 2:
输入:n = 2
输出:1
解释:根据规则,nums[0]、nums[1] 和 nums[2] 之中的最大值是 1
示例 3:
输入:n = 3
输出:2
解释:根据规则,nums[0]、nums[1]、nums[2] 和 nums[3] 之中的最大值是 2
提示:
- 0 <= n <= 100
二、思路分析:
易知结论 : 最大值一定出在奇数位。但不一定出在最后一个奇数位
例如 n = 15时,最大值在 11 的位置(为5),而不是在 15 的位置(为4)
我们不需要把每个位置都计算出来,只需要 计算我们需要用到的位置 即可。
所以采用递归的方式,从结论开始往前推,计算每一个用到的位置。 做一点点预处理的步骤,如果n为偶数,直接 n-- ,让他变成一个奇数。
算法如下:
- 如果 n 为偶, return dp[n/2]
- 如果 n 为奇, return dp[n/2]+dp[n/2+1]
- 递归终止条件,n==1 时 return 1, n==2 时 return 1
- 采用一个ans数组来记忆化存储已经计算过的值,避免重复计算。
三、AC 代码:
class Solution {
int[] ans; //记忆化数组
public int getMaximumGenerated(int n) {
if(n==0) return 0;
ans = new int[n+1];
if(n%2==0) n--;
//求取最大值
int max = 0;
for(int i=n;i>n/2;i-=2) {
max = Math.max(max, dp(i));
}
return max;
}
int dp(int n){
if(n==1) return 1;
if(n==2) return 1;
//为偶数的情况
if(n%2==0){
//若已经计算过直接返回
if(ans[n]!=0) return ans[n];
//未计算过就递归计算一次,并将中间结果存入记忆化数组
else{
int temp = dp(n/2);
ans[n] = temp;
}
}
//为奇数的情况
if(ans[n]!=0){
return ans[n];
}else{
int a = dp(n/2);
int b = dp(n/2+1);
//中间结果存储。
ans[n/2] = a;
ans[n/2+1] = b;
ans[n] = a+b;
return ans[n];
}
}
}