开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 7 天,点击查看活动详情
从仓库到码头运输箱子
原题地址
你有一辆货运卡车,你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制 和 总重量的限制 。
给你一个箱子数组 boxes 和三个整数 portsCount, maxBoxes 和 maxWeight ,其中 boxes[i] = [,] 。
- 表示第
i个箱子需要送达的码头, 是第i个箱子的重量。 portsCount是码头的数目。maxBoxes和maxWeight分别是卡车每趟运输箱子数目和重量的限制。
箱子需要按照 数组顺序 运输,同时每次运输需要遵循以下步骤:
- 卡车从
boxes队列中按顺序取出若干个箱子,但不能违反maxBoxes和maxWeight限制。 - 对于在卡车上的箱子,我们需要 按顺序 处理它们,卡车会通过 一趟行程 将最前面的箱子送到目的地码头并卸货。如果卡车已经在对应的码头,那么不需要 额外行程 ,箱子也会立马被卸货。
- 卡车上所有箱子都被卸货后,卡车需要 一趟行程 回到仓库,从箱子队列里再取出一些箱子。
卡车在将所有箱子运输并卸货后,最后必须回到仓库。
请你返回将所有箱子送到相应码头的 最少行程 次数。
示例 1:
输入:boxes = [[1,1],[2,1],[1,1]], portsCount = 2, maxBoxes = 3, maxWeight = 3
输出:4
解释:最优策略如下:
- 卡车将所有箱子装上车,到达码头 1 ,然后去码头 2 ,然后再回到码头 1 ,最后回到仓库,总共需要 4 趟行程。
所以总行程数为 4 。
注意到第一个和第三个箱子不能同时被卸货,因为箱子需要按顺序处理(也就是第二个箱子需要先被送到码头 2 ,然后才能处理第三个箱子)。
示例 2:
输入:boxes = [[1,2],[3,3],[3,1],[3,1],[2,4]], portsCount = 3, maxBoxes = 3, maxWeight = 6
输出:6
解释:最优策略如下:
- 卡车首先运输第一个箱子,到达码头 1 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第二、第三、第四个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第五个箱子,到达码头 3 ,回到仓库,总共 2 趟行程。
总行程数为 2 + 2 + 2 = 6 。
示例 3:
输入:boxes = [[1,4],[1,2],[2,1],[2,1],[3,2],[3,4]], portsCount = 3, maxBoxes = 6, maxWeight = 7
输出:6
解释:最优策略如下:
- 卡车运输第一和第二个箱子,到达码头 1 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第三和第四个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第五和第六个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
总行程数为 2 + 2 + 2 = 6 。
示例 4:
输入:boxes = [[2,4],[2,5],[3,1],[3,2],[3,7],[3,1],[4,4],[1,3],[5,2]], portsCount = 5, maxBoxes = 5, maxWeight = 7
输出:14
解释:最优策略如下:
- 卡车运输第一个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第二个箱子,到达码头 2 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第三和第四个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第五个箱子,到达码头 3 ,然后回到仓库,总共 2 趟行程。
- 卡车运输第六和第七个箱子,到达码头 3 ,然后去码头 4 ,然后回到仓库,总共 3 趟行程。
- 卡车运输第八和第九个箱子,到达码头 1 ,然后去码头 5 ,然后回到仓库,总共 3 趟行程。
总行程数为 2 + 2 + 2 + 2 + 3 + 3 = 14 。
提示:
1 <= boxes.length <=1 <= portsCount, maxBoxes, maxWeight <= 1051 <=<= portsCount1 <=<= maxWeight
思路分析
- 题目采用动态规划加滑动窗口来解决;
- 定义 result,其中 result[i] 表示区间 [0,i] 内的最少行程次数;那么
result[i] = result[j] + port(j+1, i) + 2,而port(j+1, i)表示j+1到i的码头个数; - 可以知道
result[i]是单调不减函数,然后根据题目中的条件限制maxBoxes < i - j + 1和w > maxWeight,向前移动j和计算更新port值; - 根据递推公式
result[i] = result[j] + port(j+1, i)计算每个result[i]的值。result[len]即为结果。
AC 代码
/**
* @param {number[][]} boxes
* @param {number} portsCount
* @param {number} maxBoxes
* @param {number} maxWeight
* @return {number}
*/
var boxDelivering = function(boxes, portsCount, maxBoxes, maxWeight) {
const len = boxes.length
boxes.unshift([-1, 0])
const result = Array(len + 1).fill(Infinity)
result[0] = 0
let j = 0
let weightSum = 0
let tripSum = 0
let lastPort = -1
let lastj = 0
for (let i = 1; i <= len; i++) {
while (
j + 1 <= len &&
j + 1 - i + 1 <= maxBoxes &&
weightSum + boxes[j + 1][1] <= maxWeight
) {
j += 1
weightSum += boxes[j][1]
if (boxes[j][0] != boxes[j - 1][0]) tripSum += 1
if (boxes[j][0] != lastPort) {
lastPort = boxes[j][0]
lastj = j
}
}
result[j] = Math.min(result[j], result[i - 1] + tripSum + 1)
if (j + 1 <= len && boxes[j][0] == boxes[j + 1][0]) {
result[lastj - 1] = Math.min(result[lastj - 1], result[i - 1] + tripSum)
}
weightSum -= boxes[i][1]
tripSum -= Number(i + 1 <= len && boxes[i][0] != boxes[i + 1][0])
}
return result[len]
};
结果:
- 执行结果: 通过
- 执行用时:196 ms, 在所有 JavaScript 提交中击败了100.00%的用户
- 内存消耗:77 MB, 在所有 JavaScript 提交中击败了100.00%的用户
- 通过测试用例:39 / 39