劍指offer 12 矩陣中的路徑(java)

面試題12. 矩陣中的路徑

題目描述
請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格子。例如,在下面的3×4的矩陣中包含一條字符串“bfce”的路徑(路徑中的字母用加粗標出)。

[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]

但矩陣中不包含字符串“abfb”的路徑,因爲字符串的第一個字符b佔據了矩陣中的第一行第二個格子之後,路徑不能再次進入這個格子。

解題思路:

本問題是典型的矩陣搜索問題,可使用 深度優先搜索(DFS)+ 剪枝 解決。

算法原理:

深度優先搜索: 可以理解爲暴力法遍歷矩陣中所有字符串可能性。DFS 通過遞歸,先朝一個方向搜到底,再回溯至上個節點,沿另一個方向搜索,以此類推。

剪枝: 在搜索中,遇到 這條路不可能和目標字符串匹配成功 的情況(例如:此矩陣元素和目標字符不同、此元素已被訪問),則應立即返回,稱之爲 可行性剪枝 。

思路參考:jyd

算法流程

遞歸參數: i,j爲將matrix抽象成二維矩陣時 當前訪問的行列索引; index時當前str待匹配的字符位置;

終止條件:

  1. false:1)當前矩陣訪問越界, 2)當前字符串越界 ,3)當前訪問的矩陣中的位置與str中待匹配的位置 不匹配。
  2. true: 匹配到str最後一個元素,即index == str.length-1

遞歸工作:

  1. 標記當前矩陣元素:判斷當前訪問元素是否匹配, 爲防止再次訪問,想要將當前的matrix[i * cols + j] 設置成一個新的值;
  2. 搜索下一單元格: 深度遍歷,遞歸的判斷上下左右四個方向是否滿足匹配;
  3. 還原當前矩陣元素:判斷完當前元素的四個方向後,需將matrix[i * cols + j]設置回原來的值;
public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        if(rows * cols <= 0|| str.length < 1) return false;
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                // 找第一個匹配的元素
                if(matrix[i * cols + j] == str[0]){
                    if (dfs(matrix, rows, cols, i, j , str, 0)) return true;
                }
            }
        }
        return false;
    }
    /*
    遞歸參數: i,j爲將matrix抽象成二維矩陣時 當前訪問的行列索引; index時當前str待匹配的字符位置;
    終止條件: 
        1)false:1. 當前矩陣訪問越界, 2)當前字符串越界 ,3)當前訪問的矩陣中的位置與str中待匹配的位置 不匹配。
        2)true: 匹配到str最後一個元素,即index == str.length-1
    遞歸工作: 1) 標記當前矩陣元素:判斷當前訪問元素是否匹配, 爲防止再次訪問,想要將當前的matrix[i * cols + j] 設置成一個新的值;
             2) 搜索下一單元格:  深度遍歷,遞歸的判斷上下左右四個方向是否滿足匹配;
             3) 還原當前矩陣元素:判斷完當前元素的四個方向後,需將matrix[i * cols + j]設置回原來的值;
    */
    boolean dfs(char[] matrix, int rows, int cols, int i, int j ,char[] str, int index){
        if(i < 0 || j <0 || i>= rows || j >= cols|| (i*cols + j) > (rows * cols -1) || index < 0 || matrix[i*cols+j] != str[index]){
            return false;
        }
        if(index >= str.length-1) return true;
        char temp = matrix[i * cols + j];
        matrix[i * cols + j] = '/';
        boolean res = dfs(matrix, rows, cols, i+1, j, str, index+1)||dfs(matrix, rows, cols, i, j-1, str, index+1)||
            dfs(matrix, rows, cols, i-1, j, str, index+1) || dfs(matrix, rows, cols, i, j+1, str, index+1);
        matrix[i * cols + j] = temp;
        return res;
    }

}

複雜度

M,N 分別爲矩陣行列大小, K 爲字符串 str 長度。

時間複雜度 O(3^KMN): 最差情況下,需要遍歷矩陣中長度爲 K 字符串的所有方案(搜索中每個字符有上、下、左、右四個方向可以選擇,捨棄回頭(上個字符)的方向,剩下 3 種選擇,因此方案數的複雜度爲 O(3^K)O(3 K),時間複雜度爲 O(3^K);矩陣中共有 MN 個起點,時間複雜度爲O(MN) 。

空間複雜度 O(K) : 搜索過程中的遞歸深度不超過 K ,因此係統因函數調用累計使用的棧空間佔用O(K) (因爲函數返回後,系統調用的棧空間會釋放)。最壞情況下 K = MN ,遞歸深度爲MN ,此時系統棧使用 O(MN) 的額外空間。

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