最短路徑(javascript實現)

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;
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章