dijkstra
算法的基本思想是贪⼼,每次都遍历所有邻居,并从中找到距离最⼩的,
本质上是⼀种⼴度优先遍历。这⾥我们借助堆这种数据结构。
class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
List<int[]>[] graph = buildGraph(times, n);
int[] minDistance = dijkstra(graph, k);
int res = 0;
for(int i = 1; i < minDistance.length; i++){
if(minDistance[i] == Integer.MAX_VALUE){
return -1;
}
res = Math.max(res, minDistance[i]);
}
return res;
}
public List<int[]>[] buildGraph(int[][] times, int n){
List<int[]>[] graph = new ArrayList[n+1];
for(int i = 0; i <= n; i++){
graph[i] = new ArrayList<>();
}
for(int[] time : times){
int from = time[0];
int to = time[1];
int weight = time[2];
graph[from].add(new int[]{to,weight});
}
return graph;
}
public int[] dijkstra(List<int[]>[] graph, int start){
Queue<State> pq = new PriorityQueue<>((o1,o2) -> {
return Integer.compare(o1.disTo, o2.disTo);
});
//记录最小距离
int[] minDistance = new int[graph.length];
Arrays.fill(minDistance, Integer.MAX_VALUE);
minDistance[start] = 0;
//开启dijkstra算法核心
pq.offer(new State(start, 0));
while(!pq.isEmpty()){
State node = pq.poll();
if(node.disTo > minDistance[node.id]){
continue;
}
for(int[] nextNode : graph[node.id]){
int nextId = nextNode[0];
int disToNext = nextNode[1] + node.disTo;
if(disToNext >= minDistance[nextId]){
continue;
}
pq.offer(new State(nextId, disToNext));
minDistance[nextId] = disToNext;
}
}
return minDistance;
}
}
class State{
public int id;
public int disTo;
State(int id, int disTo){
this.id = id;
this.disTo = disTo;
}
}
floyd
floyed 算法
判断从i到j 是否有路径。
判断从i 途径 mid 到j是否有路径。
查询从任意的i 到任意的j 是否有路径。
i 到 j 的最短路径 = i 到 k 的最短路径 + k 到 j 的最短路径的最小值
floyd_warshall 算法由于使⽤了动态规划的思想而不是贪心,因此其可以处理负权重的情况
class Solution {
public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
boolean[][] dp = new boolean[numCourses][numCourses];
List<Boolean> res = new ArrayList<>();
for(int[] require : prerequisites){
dp[require[0]][require[1]] = true;
}
for(int mid = 0; mid < numCourses; mid++){
for(int i = 0; i < numCourses; i++){
for(int j = 0; j < numCourses; j++){
dp[i][j] = dp[i][j] || (dp[i][mid] && dp[mid][j]);
}
}
}
for(int i = 0;i < queries.length; i++){
if(dp[queries[i][0]][queries[i][1]]){
res.add(true);
}else{
res.add(false);
}
}
return res;
}
}
因为没环,直接上dfs,都不用统计visited(map也帮忙记录了visited情况。注意使用后序遍历,不然超时,注意避免重叠子问题的计算。
class Solution {
public List<Boolean> checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) {
List<Integer>[] graph = buildGraph(prerequisites, numCourses);
Map<Integer,Set<Integer>> map = new HashMap<>();
List<Boolean> res = new ArrayList<>();
for(int[] query : queries){
if(!map.containsKey(query[0])){
Set<Integer> set = new HashSet<>();
dfs(graph, map, query[0]);
}
if(map.get(query[0]).contains(query[1])){
res.add(true);
}else{
res.add(false);
}
}
return res;
}
public List<Integer>[] buildGraph(int[][] prerequisites, int numCourses){
List<Integer>[] graph = new ArrayList[numCourses];
for(int i = 0; i < numCourses; i++){
graph[i] = new ArrayList<>();
}
for(int[] pre : prerequisites){
graph[pre[0]].add(pre[1]);
}
return graph;
}
public Set<Integer> dfs(List<Integer>[] graph, Map<Integer,Set<Integer>> map,int course){
Set<Integer> set = new HashSet();
for(int nextCourse : graph[course]){
if(map.containsKey(nextCourse)){
set.add(nextCourse);
set.addAll(map.get(nextCourse));
}else{
set.add(nextCourse);
set.addAll(dfs(graph, map, nextCourse));
}
}
map.put(course, set);
return set;
}
}