劍指offer 學習筆記 回溯法

2021-10-02 20:35:35 字數 3120 閱讀 1276

回溯法可以看成蠻力法的公升級版,它從解決問題的每一步的所有可能選項裡系統地選擇乙個可行的解決方案。回溯法適合由多個步驟組成的問題,並且每個步驟有多個選項。

用回溯法解決的問題的所有選項可以用樹狀結構形象地表示,在某一步有n個可能的選項,那麼該步驟可以看做樹狀結構中的乙個節點,每個選項看成樹中節點連線線,經過這些連線線可以到達該節點的n個子節點。樹的葉節點對應著終極狀態,如果葉節點的狀態滿足題目約束條件,那麼就找到了乙個可行方案。如果葉節點的狀態不滿足約束方程,那麼只好回溯到它的上乙個節點再嘗試其他選項。如果上乙個節點的所有選項都已嘗試過仍然不能到達滿足約束條件的終結狀態,則再次回溯到上乙個節點。如果所有節點的所有選項都嘗試過仍不能滿足題目的約束條件,則該問題無解。

通常回溯法適合用遞迴實現。

面試題12:矩陣中的路徑。請設計乙個函式,用來判斷在乙個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意一格開始,每一步可以在矩陣中向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格仔。如以下矩陣包含字串「bfce」的路徑,不包含「abfb」的路徑。

首先在矩陣中選擇乙個格仔作為路徑起點。假設路徑中某格仔的字元為ch,並且這個格仔將對應於路徑上第i個字元,假設路徑上第i個字元不是ch,那麼這個格仔不可能處在路徑上第i個位置,如果路徑上的第i個字元正好是ch,那麼到此格仔的相鄰格仔上尋找第i+1個字元。除矩陣邊界上的格仔外,其他格仔都有4個相鄰的格仔。重複這個過程。

由於回溯法的遞迴特性,路徑可以看成乙個棧,當在矩陣中定位了路徑中前n個字元的位置之後,在與第n個字元對應的格仔周圍都沒有找到第n+1個字元,這時只好返回路徑上第n-1個字元,重新定位第n個字元。

由於路徑不能重複進入相同格仔,還需定義和字元矩陣大小一樣的布林值矩陣,來標識路徑是否已經進入過。

以下為**實現:

#include

using

namespace std;

bool

haspathcore

(const

char

*matrix,

int rows,

int cols,

int row,

int col,

const

char

*str,

bool

*visited,

int&pathlength)

bool haspath =

false

;// 當row和col未越界並且當前格仔值與str當前位置的值相等並且此格仔未被訪問過,說明這個格仔暫時有效

if(row >=

0&& col >=

0&& row < rows && col < cols && matrix[row * cols + col]

== str[pathlength]

&&!visited[row * cols + col])}

return haspath;

}bool

haspath

(const

char

* matrix,

int rows,

int cols,

const

char

* str)

bool

* visited =

newbool

[rows * cols]

;// 儲存路徑上訪問過的節點

memset

(visited,

false

, rows * cols)

;// 將visited中的值初始化為false,注意第三個引數是位元組數,但bool值所佔大小為1位元組,因此位元組數等於布林值數量

int pathlength =0;

// 路徑長度

for(

int row =

0; row < rows;

++row)}}

delete

visited;

return

false;}

intmain()

else

return0;

}

面試題13:機械人的運動範圍。地上有乙個m行n列的方格。規定左下角的格仔座標為(0,0),乙個機械人從座標(0,0)的格仔開始移動,它每次可以向左、右、上、下移動一格,但不能進入行座標和列座標的數字之和大於k的格仔。例如,當k=18時,機械人能夠進入方格(35,37),因為3+5+3+7=18。但它不能進入方格(35,38),因為3+5+3+8=19。請問該機械人能夠到達多少個格仔?

和前面題目類似,這個方格也可以看作乙個m*n的矩陣,同樣,在這個矩陣中,除邊界上的格仔外,其他格仔都有4個相鄰的格仔:

#include

using

namespace std;

intgetdigitsum

(int num)

return sum;

}int

movingcountcore

(int threshold,

int rows,

int cols,

int row,

int col,

bool

* visited)

return count;

}int

movingcount

(int threshold,

int rows,

int cols)

bool

* visited =

newbool

[rows * cols]

;// 儲存已經計算過的格仔

memset

(visited,

false

, rows * cols)

;int count =

movingcountcore

(threshold, rows, cols,0,

0, visited)

;delete

visited;

return count;

}int

main()

劍指offer 回溯法

面試題12 矩陣中的路徑 上下左右遞迴,在看邊界條件 include includeusing namespace std 遞迴 bool haspathcore char m,int row,int col,int i,int j,const char str,int pathlen,bool v...

劍指offer 回溯法

題目描述 請設計乙個函式,用來判斷在乙個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中的任意乙個格仔開始,每一步可以在矩陣中向左,向右,向上,向下移動乙個格仔。如果一條路徑經過了矩陣中的某乙個格仔,則該路徑不能再進入該格仔。例如 矩陣中包含一條字串 bcced 的路徑,但是矩陣中不包含...

劍指offer 回溯法總結

面試題12 13是接連的兩道回溯法的題。先上定義 回溯法的基本行為是搜尋,搜尋過程使用剪枝函式來為了避免無效的搜尋。剪枝函式包括兩類 1.使用約束函式,剪去不滿足約束條件的路徑 2.使用限界函式,剪去不能得到最優解的路徑。回溯法說白了就是遞迴,遞迴法演算法簡潔且執行效率高,但是與之相應的就是遞迴法一...