劍指 Offer 12. 矩陣中的路徑

劍指 Offer 12. 矩陣中的路徑

請設計一個函數,用來判斷在一個矩陣中是否存在一條包含某字符串全部字符的路徑。路徑能夠從矩陣中的任意一格開始,每一步能夠在矩陣中向左、右、上、下移動一格。若是一條路徑通過了矩陣的某一格,那麼該路徑不能再次進入該格子。例如,在下面的3×4的矩陣中包含一條字符串「bfce」的路徑(路徑中的字母用加粗標出)。golang

[["a","b","c","e"],
["s","f","c","s"],
["a","d","e","e"]]數組

但矩陣中不包含字符串「abfb」的路徑,由於字符串的第一個字符b佔據了矩陣中的第一行第二個格子以後,路徑不能再次進入這個格子。函數

示例 1:設計

輸入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
輸出:true

示例 2:code

輸入:board = [["a","b"],["c","d"]], word = "abcd"
輸出:false

思路

golang

這是矩陣中的搜索問題,能夠採用 深度優先遍歷DFS+剪枝函數的思想:在長度爲i,寬度爲j的board數組中查找一條路徑使得長度爲k的word字符串知足。遞歸

DFS 解析:索引

  • 遞歸參數: 當前元素在矩陣 board 中的行列索引 i 和 j ,當前目標字符在 word 中的索引 k 。
  • 終止條件:
  • 返回 false : (1) 行或列索引越界 (2) 當前矩陣元素與目標字符不一樣 (3) 當前矩陣元素已訪問過 ( (3) 可合併至 (2) ) 。
  • 返回 true : k = len(word) - 1 ,即字符串 word 已所有匹配。
  • 遞推工做:
    標記當前矩陣元素: 將 board(i)(j)修改成空字符 ,表明此元素已訪問過,防止以後搜索時重複訪問。 搜索下一單元格: 朝當前元素的 上、下、左、右 四個方向開啓下層遞歸,使用 鏈接 (表明只需找到一條可行路徑就直接返回,再也不作後續 DFS ),並記錄結果至 res 。 還原當前矩陣元素: 將 board(i)(j)元素還原至初始值,即 word[k] 。
    返回值: 返回布爾量 res ,表明是否搜索到目標字符串。

時間複雜度 :M,N 分別爲矩陣行列大小, K爲字符串 word長度。則時間複雜度爲O(3KMN) : 最差狀況下,須要遍歷矩陣中長度爲 K字符串的全部方案,時間複雜度爲 O(3K),設字符串長度爲 K,搜索中每一個字符有上、下、左、右四個方向能夠選擇,捨棄回頭(上個字符)的方向,剩下3種選擇,所以方案數的複雜度爲 O(3K) 。矩陣中共有 MN 個起點,時間複雜度爲 O(MN) 。leetcode

空間複雜度:搜索過程當中的遞歸深度不超過 K,所以系統因函數調用累計使用的棧空間佔用 O(K)字符串

func exist(board [][]byte, word string) bool {
	rows, cols := len(board), len(board[0])
	for i := 0; i < rows; i++ {
		for j := 0; j < cols; j++ {
			if dfs(board, word, i, j, 0) {
				return true
			}
		}
	}
	return false
}

func dfs(board [][]byte, word string, i, j, k int) bool {
	rows, cols := len(board), len(board[0])
	//遞歸終止條件(返回false):索引i,j超出邊界;board[i][j]!=word[k];當前元素已經被訪問過 剪枝函數
	if i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k] {
		return false
	}
	//遞歸終止條件(返回true):k = len(word)-1
	if k == len(word)-1 {
		return true
	}
	//填充已經被遍歷過的元素,防止重複訪問
	board[i][j] = ' '

	//上下左右 找到一條知足的路徑便可
	res := dfs(board, word, i+1, j, k+1) || dfs(board, word, i, j+1, k+1) || dfs(board, word, i-1, j, k+1) || dfs(board, word, i, j-1, k+1)
	board[i][j] = word[k]
	return res
}

js

/**
 * @param {character[][]} board
 * @param {string} word
 * @return {boolean}
 */
var exist = function(board, word) {
    let rows = board.length,cols = board[0].length;
    
    var dfs = function (board,word,i,j,k) {
        //判斷遞歸終止條件(返回false):索引超出邊界 || board[i][j] = word[k] || 當前元素已經訪問過
        if (i>=rows || i <0 || j >=cols || j<0 || board[i][j]!=word[k]) return false;
        //遞歸終止條件(返回true) word中最後一個字符已經被查找到 k = word.length - 1
        if (k == word.length-1) return true;
        //標記已經訪問
        board[i][j] = ' ';
        //上下左右 只要存在一條路徑便可
        let res = dfs(board,word,i+1,j,k+1) || dfs(board,word,i,j+1,k+1) || dfs(board,word,i-1,j,k+1) || dfs(board,word,i,j-1,k+1)
        //恢復當前訪問過的元素
        board[i][j] = word[k];
        return res;
    }

    //在board二維數組中查詢長度爲k的word的路徑
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            if(dfs(board,word,i,j,0)) return true;
        }
    }

    return false;
};
相關文章
相關標籤/搜索