「矩陣中的路徑」 和 "機械人的運動範圍"是劍指offer的倒數第2,3道題目,因為這兩道題思路類似,就放在一起說。
請設計乙個函式,用來判斷在乙個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格仔。例如,在下面的3×4的矩陣中包含一條字串「bfce」的路徑(路徑中的字母用加粗標出)。
[[「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
解題思路:
這個題是路徑規劃問題,給定乙個矩陣地圖和一條路,判斷這個地圖裡面是否存在一條路徑和題目所給這條路完全匹配。
既然是路徑規劃,很容易想到用到遞迴+回溯,因為每個矩陣中的每個格仔可能被多條不同的路徑經過,所以每條路徑用完這個格仔之後要將其復原,因此需要乙個二維bool型陣列,來標記格仔是否被走過,這是回溯法的常規套路。
有了上面的思路,我們就來進行匹配。題目給定乙個字串word,那我們就從矩陣的第乙個位置( board[0][0] )開始匹配,每次走完乙個字元,下乙個字元我們有四種選擇:往上,往下,往左,往右。
所以遞迴主體就要包含這四種情況,但是別忘了上面說的,走乙個字元就要做乙個標記,也即是二維陣列的該位置標記,遞迴完後進行復原,給其他路徑去用。
那遞迴主體確定了之後,就要進行邊界判斷,因為遞迴也就包含兩部分:邊界+主體。那邊界就很簡單了,既然上面分析了乙個字元有四種走法,那肯定不能跑出界,也不能有小於0的情況,並且!每個路徑用過的格仔 本路徑不能再用,也即是每個格仔在每條路徑中只能用一次(這是題目條件)。
因此,總結一下邊界條件:① 越界 ② 走過的格仔不能再走 ③匹配過程中某個值不相等,那就直接return false。
如果上面的情況都沒有發生,那就說明匹配過程很順利,直接走完題目所給的路徑,那麼return true。
下面開始寫**:用乙個變數index跟蹤題目所給的路徑,逐個字元匹配,當index = word.length( )時,return true;
class
solution
vector
bool
>>
vis(board.
size()
, vector<
bool
>
(board[0]
.size()
,false))
;//標記陣列
for(
int i =
0; i < board.
size()
;++i)}}
return
false;}
bool
dfs(vector
char
>>
&board, string &word,
int x,
int y,
int index, vector
bool
>>
&vis)
if(x <
0|| x >= board.
size()
|| y <
0|| y >= board[0]
.size()
|| vis[x]
[y])
if(board[x]
[y]!= word[index]
)//下面是遞迴+回溯,也就是匹配的過程
vis[x]
[y]=
true
;//用了就做標記
bool res =
dfs(board, word, x +
1, y, index +
1, vis)
||dfs
(board, word, x -
1, y, index +
1, vis)
||dfs
(board, word, x, y +
1, index +
1, vis)
||dfs
(board, word, x, y -
1, index +
1, vis)
; vis[x]
[y]=
false
;//復原,給其他路徑用
return res;}}
;
這個思路是比較容易想的,不會太複雜。但是在leetcode中需要注意超時的情況,一開始我傳參的時候,第乙個引數board沒有傳引用,直接傳值,結果一直超時,在時間複雜度較大的時候,一定要盡量優化,傳引用省去了值拷貝的過程,因此可以accept。
地上有乙個m行n列的方格,從座標 [0,0] 到座標 [m-1,n-1] 。乙個機械人從座標 [0, 0] 的格仔開始移動,它每次可以向左、右、上、下移動一格(不能移動到方格外),也不能進入行座標和列座標的數字之和大於k的格仔。例如,當k為18時,機械人能夠進入方格 [35, 37] ,因為3+5+3+7=18。但它不能進入方格 [35, 38],因為3+5+3+8=19。請問該機械人能夠到達多少個格仔?
示例 1:
輸入:m = 2, n = 3, k = 1
輸出:3
示例 2:
輸入:m = 3, n = 1, k = 0
輸出:1
解題思路:
這個題和上乙個「矩陣中的路徑」比較類似,最重要的不同點是上乙個題是典型的路徑規劃問題,需要用到回溯法(因為可能多條路徑經過同乙個點),但是這個題不一樣,他要的是我們去判斷每乙個點是不是滿足條件(和class
solution
intcalculate
(int x)
return sum;
}void
dfs(
int m,
int n,
int k,
int x,
int y, vector
bool
>>
&vis)if(
calculate
(x)+
calculate
(y)> k)
vis[x]
[y]=
true
;//做標記
++sum;
//可用格仔+1
dfs(m, n, k, x +
1, y, vis)
;//往下
dfs(m, n, k, x -
1, y, vis)
;//往上
dfs(m, n, k, x, y +
1, vis)
;//往右
dfs(m, n, k, x, y -
1, vis)
;//往左
回溯法 矩陣中的路徑,機械人的運動範圍
回溯法是做了剪枝改進的窮舉法,適合由多個步驟組成,並且每個步驟都有多個選項組成的問題。回溯法的解空間樹到達葉結點時,如果在葉子結點的狀態滿足題目的約束條件,那麼就找到了乙個可行的解決方案。回溯二字在於,如果在解空間樹上的某個結點不滿足約束條件,那麼就退回到上一結點,再嘗試其它選項 如果全部試過都不行...
程式設計題 機械人的運動範圍
地上有乙個m行和n列的方格。乙個機械人從座標 0,0 的格仔開始移動,每一次只能向左,右,上,下四個方向中其中乙個方向移動一格,但是不能進入行座標和列座標的數字之和大於k的格仔。例如,當k為18時,機械人能夠進入方格 35,37 因為3 5 3 7 18。但是,它不能進入方格 35,38 因為3 5...
演算法題 機械人的運動範圍
題目描述 地上有乙個m行和n列的方格。乙個機械人從座標0,0的格仔開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數字之和大於k的格仔。例如,當k為18時,機械人能夠進入方格 35,37 因為3 5 3 7 18。但是,它不能進入方格 35,38 因為3 5 3 8...