Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。
因此每天刷刷LeetCode非常有必要
在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode
一、题目描述
给你一个整数数组 nums 和一个整数 k ,找出三个长度为 k 、互不重叠、且全部数字和(3 * k 项)最大的子数组,并返回这三个子数组。
以下标的数组形式返回结果,数组中的每一项分别指示每个子数组的起始位置(下标从 0 开始)。如果有多个结果,返回字典序最小的一个。
示例 1:
输入:nums = [1,2,1,2,6,7,5,1], k = 2
输出:[0,3,5]
解释:子数组 [1, 2], [2, 6], [7, 5] 对应的起始下标为 [0, 3, 5]。
也可以取 [2, 1], 但是结果 [1, 3, 5] 在字典序上更大。
二、思路分析
我们先预处理获得所有长度为k的子数组的和
对于这里面的所有和,我们要取不能相邻k个内的三个,和最大的值
说白了就是每k个最多取一个,跟打家劫舍的背包大同小异,只是需要记录路径的坐标
我们用动态规划,分别维护当前取第一个的最大值和坐标,取第二个的最大值和坐标和取第三个的最大值和坐标即可
三、代码实现
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSumOfThreeSubarrays = function(nums, k) {
var lMax = function(l1, l2){
if(l1[0] > l2[0])
return l1
return l2
}
const windows = new Array(nums.length - k + 1)
for(let i=0,j=0,s=0;i<=nums.length;i++){
if(i < k)
s += nums[i]
else{
windows[j++] = s
if(i<nums.length)
s += nums[i] - nums[i-k]
}
}
const dp = new Array(windows.length)
for(let i=0;i<dp.length;i++){
dp[i] = new Array(3)
for(let j=0;j<3;j++)
dp[i][j] = [0]
}
for(let i=0;i<windows.length;i++)
if(i < k)
if(i > 0)
dp[i][0] = lMax([windows[i], i], dp[i-1][0])
else
dp[i][0] = [windows[i], i]
else{
dp[i][0] = lMax([windows[i], i], dp[i-1][0])
dp[i][1] = lMax([dp[i-k][0][0]+windows[i], dp[i-k][0][1], i], dp[i-1][1])
if(i >= 2 * k)
dp[i][2] = lMax([dp[i-k][1][0] + windows[i], dp[i-k][1][1], dp[i-k][1][2], i], dp[i-1][2])
}
let m = 0;
let ans = new Array(3);
for(let i=0;i<windows.length;i++)
if(dp[i][2][0] > m){
m = dp[i][2][0];
for(let j=0;j<3;j++)
ans[j] = dp[i][2][j+1];
}
return ans;
};
四、总结
以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~