Kimi LeetCode 4003. 交替方向的最小路径代价 III JavaScript实现
以下是 LeetCode 4003. 交替方向的最小路径代价 III 的 JavaScript 实现:
```javascript
/**
* @param {number} m
* @param {number} n
* @param {number[][]} penalty
* @return {number}
*/
var minCost = function(m, n, penalty) {
// 最小堆实现(Dijkstra 需要)
class MinHeap {
constructor() {
this.heap = [];
}
push(val) {
this.heap.push(val);
this._siftUp(this.heap.length - 1);
}
pop() {
if (this.heap.length === 0) return null;
const top = this.heap[0];
const end = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = end;
this._siftDown(0);
}
return top;
}
_siftUp(i) {
const val = this.heap[i];
while (i > 0) {
const parent = (i - 1) >> 1;
if (this.heap[parent][0] <= val[0]) break;
this.heap[i] = this.heap[parent];
i = parent;
}
this.heap[i] = val;
}
_siftDown(i) {
const val = this.heap[i];
const len = this.heap.length;
while (true) {
let child = (i << 1) + 1;
if (child >= len) break;
const right = child + 1;
if (right < len && this.heap[right][0] < this.heap[child][0]) {
child = right;
}
if (this.heap[child][0] >= val[0]) break;
this.heap[i] = this.heap[child];
i = child;
}
this.heap[i] = val;
}
get size() {
return this.heap.length;
}
}
const dirs = [[-1, 0], [0, 1], [0, -1], [1, 0]]; // 上、右、左、下
const INF = Number.MAX_SAFE_INTEGER;
// dist[i][j][k]: 到达 (i,j) 且下一步动作奇偶性为 k 的最小成本
// k=1: 下一步是奇数动作(应向右/下)
// k=0: 下一步是偶数动作(应向左/上)
const dist = Array.from({ length: m }, () =>
Array.from({ length: n }, () => [INF, INF])
);
dist[0][0][1] = 1; // 初始在 (0,0),已付入场费 1,下一步是动作 1(奇数)
const pq = new MinHeap();
pq.push([1, 0, 0, 1]); // [cost, i, j, parity]
while (pq.size > 0) {
const [d, i, j, k] = pq.pop();
// 到达终点即是最小成本(Dijkstra 性质)
if (i === m - 1 && j === n - 1) {
return d;
}
if (d > dist[i][j][k]) continue;
const p = penalty[i][j];
// 1. 等待:支付 penalty,奇偶性翻转,位置不变
const waitCost = d + p;
if (waitCost < dist[i][j][k ^ 1]) {
dist[i][j][k ^ 1] = waitCost;
pq.push([waitCost, i, j, k ^ 1]);
}
// 2. 向四个方向移动
for (let idx = 0; idx < 4; idx++) {
const x = i + dirs[idx][0];
const y = j + dirs[idx][1];
if (x < 0 || x >= m || y < 0 || y >= n) continue;
// idx: 0=上, 1=右, 2=左, 3=下
// 奇数动作(k=1)应对应右(1)或下(3) -> idx & 1 === 1
// 偶数动作(k=0)应对应上(0)或左(2) -> idx & 1 === 0
const matched = (idx & 1) === k;
const extra = matched ? 0 : p;
const moveCost = d + (x + 1) * (y + 1) + extra;
if (moveCost < dist[x][y][k ^ 1]) {
dist[x][y][k ^ 1] = moveCost;
pq.push([moveCost, x, y, k ^ 1]);
}
}
}
return -1; // 题目保证可达
};
```
核心思路
这道题是带状态的最短路问题,用 Dijkstra 求解:
- 状态设计:`dist[i][j][k]` 表示到达 `(i,j)` 且下一步动作奇偶性为 `k` 的最小成本
- `k=1`:下一步是奇数动作,应该向右或向下移动
- `k=0`:下一步是偶数动作,应该向左或向上移动
- 两种动作:
1. 等待:支付当前格 `penalty`,奇偶性翻转
2. 移动:向四个方向之一移动。若方向符合当前奇偶性规则,只付目标格入场费 `(x+1)*(y+1)`;否则额外支付当前格 `penalty`。移动后奇偶性翻转
- 由于 JS 没有内置优先队列,代码中附带了一个二叉堆实现的最小堆
复杂度
- 时间:`O(mn · log(mn))`
- 空间:`O(mn)`
更多推荐

所有评论(0)