1. 程式人生 > 實用技巧 >leetcode 劍指offer 13 機器人的運動範圍

leetcode 劍指offer 13 機器人的運動範圍

問題描述:

地上有一個m行n列的方格,從座標 [0,0] 到座標 [m-1,n-1] 。一個機器人從座標 [0, 0] 的格子開始移動,它每次可以向左、右、上、下移動一格(不能移動到方格外),也不能進入行座標和列座標的數位之和大於k的格子。例如,當k18時,機器人能夠進入方格 [35, 37] ,因為3+5+3+7=18。但它不能進入方格[35, 38],因為3+5+3+8=19。請問該機器人能夠到達多少個格子?

解題思路:

本題與矩陣中的路徑類似,是典型的搜尋 & 回溯問題。在介紹回溯演算法演算法前,為提升計算效率,首先講述兩項前置工作:數位之和計算、可達解分析 。

數位之和計算:
設一數字x

,向下取整除法符號// ,求餘符號 ,則有:

  • x⊙10:得到x的個位數字;
  • x//10: 令x的十進位制數向右移動一位,即刪除個位數字。

由於機器人每次只能移動一格(即只能從x運動至x±1),因此每次只需計算xx±1的數位和增量。本題說明1≤n,m≤100 ,以下公式僅在此範圍適用。

(x + 1) % 10 != 0 ? s_x + 1 : s_x - 8;

方法:廣度優先遍歷 BFS

  • BFS/DFS : 兩者目標都是遍歷整個矩陣,不同點在於搜尋順序不同。

    • DFS 是朝一個方向走到底,再回退,以此類推;

    • BFS 則是按照“平推”的方式向前搜尋。

  • BFS 實現: 通常利用佇列實現廣度優先遍歷。

演算法解析:

  • 初始化: 將機器人初始點 (0, 0)(0,0) 加入佇列 queue ;

  • 迭代終止條件: queue 為空。代表已遍歷完所有可達解。

  • 迭代工作:

    • 單元格出隊: 將隊首單元格的 索引、數位和 彈出,作為當前搜尋單元格。
    • 判斷是否跳過: 若 ① 行列索引越界 或 ② 數位和超出目標值 k 或 ③ 當前元素已訪問過 時,執行 continue 。
    • 標記當前單元格 :將單元格索引 (i, j) 存入 Set visited 中,代表此單元格 已被訪問過 。
    • 單元格入隊: 將當前元素的 下方、右方 單元格的 索引、數位和 加入 queue 。
  • 返回值: Set visited

    的長度 len(visited) ,即可達解的數量。
    PS:使用了輔助變數 res 統計可達解數量;

class Solution {
public:
    int movingCount(int m, int n, int k) {
        vector<vector<bool>> v(m, vector<bool>(n, 0));
        int res = 0;
        queue<vector<int>> que;
        que.push({0, 0, 0, 0});
        while(!que.empty())
        {
            auto x = que.front();
            que.pop();
            int i = x[0], j = x[1], si = x[2], sj = x[3];
            if (i >= m || j >= n || k < si + sj || v[i][j]) continue;
            ++res;
            v[i][j] = true;
            que.push({i, j + 1, si, (j + 1) % 10 ? (sj + 1) : (sj - 8)});
            que.push({i + 1, j, (i + 1) % 10 ? (si + 1) : (si - 8), sj});
        }
        return res;
    }
};