牛客刷題回溯法之矩陣中的路徑 and 機器人的運動範圍

YAYA776發表於2020-10-05

題目描述一矩陣中的路徑

請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一個格子開始,每一步可以在矩陣中向左,向右,向上,向下移動一個格子。如果一條路徑經過了矩陣中的某一個格子,則該路徑不能再進入該格子。 例如
在這裡插入圖片描述
矩陣中包含一條字串"bcced"的路徑,但是矩陣中不包含"abcb"路徑,因為字串的第一個字元b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入該格子。
牛客連結:

https://www.nowcoder.com/practice/c61c6999eecb4b8f88a98f66b273a3cc?tpId=13&&tqId=11218&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

解題思路:

分析:回溯演算法
這是一個可以用回朔法解決的典型題。首先,在矩陣中任選一個格子作為路徑的起點。如果路徑上的第i個字元不是ch,那麼這個格子不可能處在路徑上的
第i個位置。如果路徑上的第i個字元正好是ch,那麼往相鄰的格子尋找路徑上的第i+1個字元。除在矩陣邊界上的格子之外,其他格子都有4個相鄰的格子。
重複這個過程直到路徑上的所有字元都在矩陣中找到相應的位置。
  由於回朔法的遞迴特性,路徑可以被開成一個棧。當在矩陣中定位了路徑中前n個字元的位置之後,在與第n個字元對應的格子的周圍都沒有找到第n+1個
字元,這個時候只要在路徑上回到第n-1個字元,重新定位第n個字元。
  由於路徑不能重複進入矩陣的格子,還需要定義和字元矩陣大小一樣的布林值矩陣,用來標識路徑是否已經進入每個格子。 當矩陣中座標為(row,col)的
格子和路徑字串中相應的字元一樣時,從4個相鄰的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路徑字串中下一個字元
如果4個相鄰的格子都沒有匹配字串中下一個的字元,表明當前路徑字串中字元在矩陣中的定位不正確,我們需要回到前一個,然後重新定位。
  一直重複這個過程,直到路徑字串上所有字元都在矩陣中找到合適的位置。
參考連結:

https://www.nowcoder.com/questionTerminal/c61c6999eecb4b8f88a98f66b273a3cc

程式碼:

class Solution {
public:
    bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(rows==0 || cols==0 || matrix==NULL || str==NULL) return false;
        int pathLength = 0;
        vector<bool> visited(rows*cols, false);
        for(int row=0; row<rows; row++) {
            for(int col=0; col<cols; col++) {
                if(hasPathCore(matrix, str, rows, cols, row, col, pathLength, visited)) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    bool hasPathCore(char* matrix, char* str, int rows, int cols, int row, 
                     int col, int& pathLength, vector<bool>& visited) 
    {
        if(str[pathLength] == '\0') {
            return true;
        }
        bool hasPath = false;
        
        if(row>=0 && row<rows && col>=0 && col<cols && 
           str[pathLength]==matrix[row*cols+col] && !visited[row*cols+col]) {
            pathLength++;
            visited[row*cols+col] = true;
            
            hasPath = hasPathCore(matrix, str, rows, cols, row-1, col, pathLength, visited)
              || hasPathCore(matrix, str, rows, cols, row, col-1, pathLength, visited)
              || hasPathCore(matrix, str, rows, cols, row+1, col, pathLength, visited)
              || hasPathCore(matrix, str, rows, cols, row, col+1, pathLength, visited);
            
            if(!hasPath) {
                pathLength--;
                visited[row*cols+col] = false;
            }
        }
        return hasPath;
    }
};

題目描述二 機器人的運動範圍

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

牛客連結:

https://www.nowcoder.com/practice/6e5207314b5241fb83f2329e89fdecc8?tpId=13&&tqId=11219&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

解題思路:

核心思路:
1.從(0,0)開始走,每成功走一步標記當前位置為true,然後從當前位置往四個方向探索,
返回1 + 4 個方向的探索值之和。
2.探索時,判斷當前節點是否可達的標準為:
1)當前節點在矩陣內;
2)當前節點未被訪問過;
3)當前節點滿足limit限制。
參考連結:

https://www.nowcoder.com/questionTerminal/6e5207314b5241fb83f2329e89fdecc8

程式碼:

class Solution {
public:
    int movingCount(int threshold, int rows, int cols)
    {
        if(rows<=0 || cols<=0 || threshold <=0) return 0;
        vector<bool> visited(rows*cols, false);
        int count = movingCountCore(threshold, rows, cols, 0, 0, visited);
        return count;
    }
    
    int movingCountCore(int threshold, int rows, int cols, int row, int col, 
                     vector<bool>& visited)
    {
        int count = 0;
        int sum = digitalSum(row) + digitalSum(col);
        if(row>=0 && col>=0 && row<rows && col<cols && sum<=threshold && !visited[row*cols+col]) {
            visited[row*cols+col] = true;
            count =1+ movingCountCore(threshold, rows, cols, row-1, col, visited)
                    + movingCountCore(threshold, rows, cols, row, col-1, visited)
                    + movingCountCore(threshold, rows, cols, row+1, col, visited)
                    + movingCountCore(threshold, rows, cols, row, col+1, visited);
        }
        return count;
    }
    
    int digitalSum(int num) {
        int sum = 0;
        while(num>0) {
            sum = sum + num%10;
            num = num/10;
        }
        return sum;
    }
};

注意:
回溯法

相關文章