题目地址:
https://www.lintcode.com/problem/minimum-path-sum-ii/description
给定一个二维矩阵 A A A,求从左下角到右上角的所有路径中权值和最小的路径,返回那个最小的权值和。每一步允许走四周的四个方向。权值和定义为路径上所有数字之和。
思路是Dijkstra算法。这题基本上就是Dijkstra算法的直接应用。下面简要描述二叉堆优化下的Dijkstra算法:
1、开一个class叫Pair,存坐标以及到当前坐标的路径和;
2、开一个最小堆,按照路径和来比较,小者优先,并将起点入堆;
3、堆不空则进行循环,将堆顶出堆,如果其恰好就是终点,则直接返回路径和;否则看一下其是否计算过(这里计算过的意思是到达这个位置的最短路径和有没有被计算过。Dijkstra算法的性质告诉我们,每次出堆的元素就恰好代表了最小路径和),如果计算过则跳过;否则标记其为计算过,并四个方向拓展,将新的未计算过的位置入堆。
代码如下:
import java.util.HashSet;
import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Set;
public class Solution {
class Pair {
int x, y, sum;
public Pair(int x, int y, int sum) {
this.x = x;
this.y = y;
this.sum = sum;
}
@Override
public boolean equals(Object o) {
Pair pair = (Pair) o;
return x == pair.x && y == pair.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
/**
* @param matrix: a matrix
* @return: the minimum height
*/
public int minPathSumII(int[][] matrix) {
// Write your code here
PriorityQueue<Pair> minHeap = new PriorityQueue<>((p1, p2) -> Integer.compare(p1.sum, p2.sum));
int m = matrix.length, n = matrix[0].length;
minHeap.offer(new Pair(m - 1, 0, matrix[m - 1][0]));
Set<Pair> visited = new HashSet<>();
int[] d = {1, 0, -1, 0, 1};
while (!minHeap.isEmpty()) {
Pair cur = minHeap.poll();
// 第一次出堆走到终点的路径就是权值和最小的路径,返回权值和
if (cur.x == 0 && cur.y == n - 1) {
return cur.sum;
}
// visited包含,则说明最小值已经算出来了,略过之
if (visited.contains(cur)) {
continue;
}
// 否则标记为最小值已经算出
visited.add(cur);
for (int i = 0; i < 4; i++) {
int nextX = cur.x + d[i], nextY = cur.y + d[i + 1];
if (inBound(nextX, nextY, matrix)) {
Pair next = new Pair(nextX, nextY, cur.sum + matrix[nextX][nextY]);
if (!visited.contains(next)) {
minHeap.offer(next);
}
}
}
}
return -1;
}
private boolean inBound(int x, int y, int[][] matrix) {
return 0 <= x && x < matrix.length && 0 <= y && y < matrix[0].length;
}
}
时间复杂度 O ( E log V ) O(E\log V) O(ElogV),空间 O ( V ) O(V) O(V)。