面試題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待匹配的字符位置;
終止條件:
- false:1)當前矩陣訪問越界, 2)當前字符串越界 ,3)當前訪問的矩陣中的位置與str中待匹配的位置 不匹配。
- true: 匹配到str最後一個元素,即index == str.length-1
遞歸工作:
- 標記當前矩陣元素:判斷當前訪問元素是否匹配, 爲防止再次訪問,想要將當前的matrix[i * cols + j] 設置成一個新的值;
- 搜索下一單元格: 深度遍歷,遞歸的判斷上下左右四個方向是否滿足匹配;
- 還原當前矩陣元素:判斷完當前元素的四個方向後,需將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) 的額外空間。