743. 網絡延遲時間
有 N 個網絡節點,標記為 1 到 N。
給定一個列表 times,表示信號經過有向邊的傳遞時間。 times[i] = (u, v, w),其中 u 是源節點,v 是目標節點, w 是一個信號從源節點傳遞到目標節點的時間。
現在,我們從某個節點 K 發出一個信號。需要多久才能使所有節點都收到信號?如果不能使所有節點收到信號,返回 -1。
輸入:times = [[2,1,1],[2,3,1],[3,4,1]], N = 4, K = 2
輸出:2
深度優先搜索
以K為起點,深度優先遍歷,傳入距離值,若距離大於結點已知最小距離則停止深搜,否則更新當前結點
時間復雜度:O(N^N)
空間復雜度:O(N+E)
var networkDelayTime = function (times, N, K) {
/* 存各條邊的信息 */
const edges = new Map();
for (let [x, y, val] of times) {
if (!edges.has(x))
edges.set(x, [[y, val]]);
else
edges.get(x).push([y, val]);
}
/* 初始化標記 */
const vis = new Array(N + 1).fill(false);
/* 初始化距離 */
const MAX = Number.MAX_SAFE_INTEGER;
const dst = new Map();
for (let i = 1; i <= N; i++) dst.set(i, MAX);
/* 深搜 */
function dfs(index, dis) {
/* 剪枝 */
if (dst.get(index) < dis) return;
/* 更新 */
dst.set(index, dis);
/* 往下遍歷 */
if (edges.get(index)) {
for (let [tgt, val] of edges.get(index)) {
if (!vis[tgt]) {
vis[tgt] = true;
dfs(tgt, dis + val);
vis[tgt] = false;
}
}
}
}
dfs(K, 0);
/* 取最大值 */
let ans = 0;
for (let v of dst) {
if (v[1] === MAX) return -1;
ans = Math.max(ans, v[1]);
}
return ans;
};
Dijkstra解法
每次找出距離K最近的點minIndex
並標記,遍歷minIndex
相連的所有點tgt
,對比K直接到tgt的距離
和K經過minIndex到達tgt的距離
,更新K到tgt的距離
為兩者中的最小值
,重復該操作直到所有點均已被標記
時間復雜度:由於需要N輪更新,每輪遍歷N次,所以為O(N^2)
空間復雜度:O(N+E)
var networkDelayTime = function (times, N, K) {
const edges = new Map();
const dst = new Map();
/* 轉換為起點為索引的邊進行存儲 */
for (let [x, y, val] of times) {
if (!edges.has(x)) {
edges.set(x, [[y, val]]);
} else {
edges.get(x).push([y, val]);
}
}
/* 初始化各點到K的距離 */
const MAX = Number.MAX_SAFE_INTEGER;
for (let i = 1; i <= N; i++) dst.set(i, MAX);
dst.set(K, 0);
/* 更新每個結點 */
const vis = new Array(N + 1).fill(false);
let minIndex, min;
for (let k = 1; k <= N; k++) {
/* 找最小邊 */
minIndex = -1; min = MAX;
for (let i = 1; i <= N; i++) {
if (!vis[i] && dst.get(i) < min) {
minIndex = i;
min = dst.get(i);
}
}
if (minIndex === -1) break;
/* 標記訪問並更新其他相連結點 */
vis[minIndex] = true;
if (edges.has(minIndex)) {
for (let [tgt, val] of edges.get(minIndex)) {
// 對比K直接到tgt的距離和經過minIndex到達tgt的距離
dst.set(tgt, Math.min(dst.get(tgt), dst.get(minIndex) + val));
}
}
}
/* 找最大距離 */
let ans = 0;
for (let v of dst) {
//遍歷Map的結果是一個數組
if (v[1] === MAX) return -1;//有不可到達的點
ans = Math.max(v[1], ans);
}
return ans;
};
SFPA算法
將被更新的結點放入隊列,每次取出隊頭,遍歷與其相關的所有結點,若相關結點值被更新,則放入到隊列尾部,以便下次取出來更新后續結點
時間復雜度:最壞O(V*E),V表示入隊次數
空間復雜度:O(V+E)
var networkDelayTime = function (times, N, K) {
/* 存每個節點的所有邊 */
const edges = new Map();
for (let [x, y, val] of times) {
if (!edges.has(x)) {
edges.set(x, [[y, val]]);
} else {
edges.get(x).push([y, val]);
}
}
/* 初始化距離 */
const MAX = Number.MAX_SAFE_INTEGER;
const dst = new Array(N + 1).fill(MAX);
dst[K] = 0;
/* 隊列中的元素會引起后續結點更新 */
const queue = [K];
while (queue.length) {
let x = queue.shift();
// 更新結點
if (edges.has(x)) {
for (let [y, val] of edges.get(x)) {
if (dst[y] > dst[x] + val) {
dst[y] = dst[x] + val;
queue.push(y);//存入隊列更新y以后的結點
}
}
}
}
/* 找最大值 */
let ans = 0;
for (let i = 1; i <= N; i++) {
ans = Math.max(ans, dst[i]);
}
return ans === MAX ? -1 : ans;
};