客上刷题遇到的。网上找了下,JavaScript版本的比较少,故记录下来供有需要的朋友参考。
【小红书2020年秋招前端题】
薯队长写了n篇笔记,编号从1~n,每篇笔记都获得了不少点赞数。
薯队长想从中选出一些笔记,作一个精选集合。挑选的时候有两个规则:
1.不能出现连续编号的笔记。
2.总点赞总数最多 如果满足1,2条件有多种方案,挑选笔记总数最少的那种
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void async function () {
// Write your code here
while (line = await readline()) {
// 所有笔记的数目
let len = parseInt(line);
// 每本笔记的点赞数
let arr = await readline()
arr = arr.split(" ").map(Number)
// 只有1本笔记
if (len == 1) {
console.log(arr[0],1)
} else if (len == 2) {
// 只有两本笔记
console.log(Math.max(arr[0], arr[1]),1)
} else {
// let dp = Array.from({ length: 2 }, () => new Array(len).fill(0));// 创建两行len列的数组
let dp = new Array(len).fill(0) // dp表示第i本笔记的点赞最大值
let dataDairy = new Array(len).fill(0)
dp[0] =arr[0],
dp[1]=Math.max(arr[0],arr[1])
dataDairy[0]=1,
dataDairy[1]=1
for (let i = 2; i < len; i++) {
// 点赞数,同打家劫舍。问题关键:是否选择第i本笔记
dp[i]=Math.max(dp[i-1],arr[i]+dp[i-2])
// 笔记本
if(dp[i-1]<dp[i-2]+arr[i]){
dataDairy[i]=dataDairy[i-2]+1
}else{
dataDairy[i]=dataDairy[i-1]
}
}
console.log(dp[len-1],dataDairy[len-1])
}
}
}()
【运行结果】
【解析】
问题的关键:思路同打家劫舍
(1)用dp[i],dataDairy [i]分别存放最大点赞数、选择的笔记本数。
(2)当只有一本笔记本: dp[0]=arr[0],dataDairy [0]=1
(3)只有两本笔记本: dp[1]=Math.max(arr[0],arr[1]), dataDairy [1]=1
(4)三本及以上:
若选择第i本笔记,则最大点赞数为dp[i-2]+dp[i];
若不选择第i本笔记,最大点赞数为dp[i-1]。
(5)递推公式为dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
同理,详细解析请看代码注释
参考: