[bfs廣搜] 1. 01 矩陣(bfs變種、動態規劃、巧妙解法)

1. 題目來源

鏈接:542. 01 矩陣

2. 題目說明

在這裏插入圖片描述

3. 題目解析

方法一:bfs變種+巧妙解法

按標籤刷題,是一道求 距離場 例題。給了一個只有 0 和 1 的矩陣,求每一個 1 到離其最近的 0 的距離,其實也就是求一個 距離場,而求距離場那麼 BFS 將是不二之選。

若採用暴力直接找的方法,即從每一個 0 開始遍歷,不停的更新每一個 1 的距離,但是這樣寫下來會 TLE 了。

再改變思路,從每一個 1 開始 BFS,找到最近的 0,結果還是 TLE,氣死人…

至此其實思路是對的,看了看大佬的想法,頓時醍醐灌頂,寫法上可以進一步優化即可:

  • 首先遍歷一次矩陣,將值爲 0 的點都存入 queue,將值爲 1 的點改爲 INT_MAX
  • 之前像什麼遍歷迷宮啊,起點只有一個,而這道題所有爲 0 的點都是起點,這想法 tql
  • 然後開始 BFS 遍歷,從 queue 中取出一個數字,遍歷其周圍四個點,如果越界或者周圍點的值小於等於當前值加 1,則直接跳過。因爲周圍點的距離更小的話,就沒有更新的必要,否則將周圍點的值更新爲當前值加 1,然後把周圍點的座標加入 queue 即可

參見代碼如下:

// 執行用時 :136 ms, 在所有 C++ 提交中擊敗了41.24%的用戶
// 內存消耗 :25.4 MB, 在所有 C++ 提交中擊敗了66.67%的用戶

class Solution {
public:
    int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        queue<pair<int, int>> q;
        int m = matrix.size(), n = matrix[0].size();
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) q.push({i, j});
                else matrix[i][j] = INT_MAX;
            }
        }

        while (!q.empty()) {
            auto t = q.front();
            q.pop();
            for (int i = 0; i < 4; ++i) {
                int x = t.first + dir[i][0];
                int y = t.second + dir[i][1];
                if (x < 0 or x >= m or y < 0 or y >= n or 
                    matrix[x][y] <= matrix[t.first][t.second] + 1) continue;

                matrix[x][y] = matrix[t.first][t.second] + 1;
                q.push({x, y});
            }
        }
        return matrix;
    }
};

方法二:dp+巧妙解法

LINK:思路來自官方題解

有一說一,這個 dp 解法對於瞭解 bfs 的刷題手來講大多都不是第一選擇,思考起來確實有遺漏,並且還是需要知道一定的結論才能進行到常數的優化。所以在此我感覺瞭解即可,即知道

  • 劃重點:曼哈頓距離,通過【左上到右下】和【右下到左上】的兩次狀態轉移之後,res[i][j] 的值即爲題目所求的到最近值爲 0 點的距離

這個 dp 思路很值得去思考,證明。但對於初學者來講,知道上面的結論也就差不多了,感興趣同學可自行證明該結論或是參考題解區後的相關證明。在此由於博主能力有限,就不作深究了。

參見代碼如下:

// 執行用時 :112 ms, 在所有 C++ 提交中擊敗了54.28%的用戶
// 內存消耗 :23 MB, 在所有 C++ 提交中擊敗了100.00%的用戶

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        // 初始化動態規劃的數組,所有的距離值都設置爲一個很大的數
        vector<vector<int>> dist(m, vector<int>(n, INT_MAX / 2));
        // 如果 (i, j) 的元素爲 0,那麼距離爲 0
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) {
                    dist[i][j] = 0;
                }
            }
        }
        // 只有 水平向左移動 和 豎直向上移動,注意動態規劃的計算順序
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i - 1 >= 0) dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1);
                if (j - 1 >= 0) dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1);
            }
        }
        // 只有 水平向右移動 和 豎直向下移動,注意動態規劃的計算順序
        for (int i = m - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                if (i + 1 < m) dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1);
                if (j + 1 < n) dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1);
                
            }
        }
        return dist;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章