[マトリックスパス]バックトラックの書き方がわかりませんか?テンプレートを見てください!
過去数日間にいくつかのバックトラッキングアルゴリズムのトピックを実行しましたが、再帰の主要なステップの結果を理解することが非常に重要であることがわかりました。一連のテンプレートを見つけようとしました。考え方は、優れたフレームワークを構築することです。 、そして徐々にそれについて考えます。最初に、単純なバックトラッキングアルゴリズムの問題を段階的にゆっくりと見ていきましょう。
1.マトリックスパス
タイトル説明:
ステップバイステップで分析してみましょう:
まず、2つのforループで開始位置を見つけます。コードは次のとおりです。
bool exist(vector<vector<char>>& board, string word) {
if(word.empty())
return true;
rows=board.size();
cols=board[0].size();
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
{
if(hasPathCore(board,word,i,j,0))
return true;
}
return false;
}
理解するのが難しいのは、トレースバック関数hasPathCoreです。
最初のステップは、関数の終了の条件を見つけることです(成功した終了、失敗した終了)
終了条件の失敗:範囲外、文字の不一致
if(row>=rows || col>=cols || row<0 || col<0 ||word[pathLength]!=board[row][col])
return false;
正常に終了するための条件:下部を見つける(ほとんどのバックトラッキングアルゴリズムに適用可能)
if(pathLength==word.size()-1)//查找到最后,或者已近查找过了返回真
return true;
2番目のステップは、次の再帰の条件を記述することです。
この時点で、文字の位置が正しく検出され、上下左右に検索できます。これは、各ノードに4つの子ノードがあり、木が私たちを横切っていると考えるのが最も簡単なのは再帰です。見てみましょう。
boolean dfs(char[][] board, char[] word, int row, int col, int pathLength) {
if (边界条件的判断) {
return;
}
一些逻辑处理
bool haspath;
//往右
haspath = dfs(board, word, i + 1, j, pathLength + 1)
//往左
||dfs(board, word, i - 1, j, pathLength + 1)
//往下
||dfs(board, word, i, j + 1, pathLength + 1)
//往上
||dfs(board, word, i, j - 1, pathLength + 1);
//上面4个方向,只要有一个能查找到,就返回true;
一些逻辑处理
return res;
}
3番目のステップは論理処理を追加することです
この時点で、コードには一般的なフレームワークがあります。コードに従うために、開始状態、中間障害状態、および終了状態の3つの状態を個別に呼び出しました。
開始状態:最初に一致する文字列を見つけます。問題ありません。
中間障害ステータス:dfsにすべての障害、つまり赤いボックスを検出させます。
このとき、コードロジックはバックトラッキングの最も重要な部分である黄色のボックス1に戻り、黄色のボックス2にリンクしてロジックを実行します。
この時点で、それが元に戻らないようにすることがわかっています。また、ロジック1とロジック2の操作は相対的であり、エンキューとデキュー、変更と復元、重要なポイントを理解します。コードを初期状態の1に戻します。以下の間に特定の情報を追加します。
bool hasPathCore(vector<vector<char>>& board, string word, int row,int col,int pathLength)
{
if(row>=rows || col>=cols || row<0 || col<0 ||word[pathLength]!=board[row][col])
return false;
if(pathLength==word.size()-1)
//查找到最后,或者已近查找过了返回真
return true;
board[row][col]='\0';
//与之前的if语句对应,表示下个坐标为【i,j】的情况已近走过了,直接返回,防止接下来的语句搜索过程走回头路。
bool haspath=hasPathCore(board,word,row-1,col,pathLength+1)
||hasPathCore(board,word,row,col-1,pathLength+1)
||hasPathCore(board,word,row+1,col,pathLength+1)
||hasPathCore(board,word,row,col+1,pathLength+1);
//千万不能写pathLength++!!
board[row][col]=word[pathLength];
//因为只代表此次搜索过程中,该元素已访问过,当初始cow,col变化时,又开始了另一次搜索过程(假word=bfsa的情况辅助理解)
return haspath;
}
- board [row] [col] = '\ 0'は、[row、col]が近くにあり、次回戻るのを防ぐことを意味します
- board [row] [col] = word [pathLength]は、[row、col]周辺のすべての検索が失敗し、[row、col]の状態が復元されて、このポイントを見つける次の開始点でのエラーを防止することを意味します。
終了状態:最後の文字列を見つけてすべて成功すると、関数は直接trueを返します。問題はありません。
4番目のステップ、おめでとうございます!
完全なコード:
class Solution {
public:
int rows=0;
int cols=0;
bool exist(vector<vector<char>>& board, string word) {
if(word.empty())
return true;
rows=board.size();
cols=board[0].size();
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
{
if(hasPathCore(board,word,i,j,0))
return true;
}
return false;
}
bool hasPathCore(vector<vector<char>>& board, string word, int row,int col,int pathLength)
{
if(row>=rows || col>=cols || row<0 || col<0 ||word[pathLength]!=board[row][col])
return false;
if(pathLength==word.size()-1)//查找到最后,或者已近查找过了返回真
return true;
board[row][col]='\0'; //与之前的if语句对应,表示下个坐标为【i,j】的情况已近走过了,直接返回,防止接下来的语句搜索过程走回头路。
bool haspath=hasPathCore(board,word,row-1,col,pathLength+1)||hasPathCore(board,word,row,col-1,pathLength+1)||hasPathCore(board,word,row+1,col,pathLength+1)||hasPathCore(board,word,row,col+1,pathLength+1); //千万不能写pathLength++!!
board[row][col]=word[pathLength]; //因为只代表此次搜索过程中,该元素已访问过,当初始i j变化时,又开始了另一次搜索过程(假设word=bfsa的情况辅助理解)
return haspath;
}
};
同じことが他のトピックにも当てはまります。それが皆さんのお役に立てば幸いです。
電話番号の文字の組み合わせ
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations;
if (digits.empty()) {
return combinations;
}
unordered_map<char, string> phoneMap{
{
'2', "abc"},
{
'3', "def"},
{
'4', "ghi"},
{
'5', "jkl"},
{
'6', "mno"},
{
'7', "pqrs"},
{
'8', "tuv"},
{
'9', "wxyz"}
};
string combination;
backtrack(combinations, phoneMap, digits, 0, combination);
return combinations;
}
void backtrack(vector<string>& combinations, const unordered_map<char, string>& phoneMap, const string& digits, int index, string& combination) {
if (index == digits.length())
{
combinations.push_back(combination);
}
else
{
char digit = digits[index];
const string& letters = phoneMap.at(digit);
for (const char& letter: letters)
{
combination.push_back(letter);
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.pop_back();
}
}
}
};