回朔算法的思想很簡單,每一步都是嘗試,如果正確進行下一步,如果不正確則回退,回退到上一步或者原點。 爲了優化時間,不必要的搜索要進行剪枝操作
常見的深度優先搜索就是回朔法的思想,來幾道經典的回朔法。
1.https://leetcode-cn.com/problems/combination-sum/ 代碼有註釋,今天時間緊急,後邊有時間畫圖放上邊加以理解
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> tmp;
sort(candidates.begin(), candidates.end()); //排序,也是爲了剪枝
int len = candidates.size();
combinationSumCore(res, candidates, target, tmp, 0, 0, len);
return res;
}
void combinationSumCore(vector<vector<int>> &res, vector<int>& candidates, int target, vector<int>& tmp, int sum, int begin, int len){
if(sum == target) //如果sum等於目標值 則將tmp的vector放到res中
res.push_back(tmp);
else
{
for(int i = begin; i < len; i++)
{
if(candidates[i] + sum <= target)
{
tmp.push_back(candidates[i]);
combinationSumCore(res, candidates, target, tmp, candidates[i] + sum, i, len); //可以被無限重複的選,則i還是原來的座標
tmp.pop_back(); //回朔,一步一步回到 符合要求的一步 或者 返回到第一層i = begin 這一步
}
else //剪枝操作
break;
}
}
}
};
2.https://leetcode-cn.com/problems/combination-sum-ii/
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
vector<vector<int>> res;
vector<int> tmp;
sort(candidates.begin(), candidates.end());
int len = candidates.size();
combinationSumCore(res, candidates, target, tmp, 0, 0);
return res;
}
void combinationSumCore(vector<vector<int>> &res, vector<int>& candidates, int target, vector<int>& tmp, int sum, int begin){
if(sum == target){
res.push_back(tmp);
}
else
{
for(int i=begin; i<candidates.size(); ++i) //整個一輪返回來,當i = 1, 就會去重複了 稍微有點繞
{
if(sum+candidates[i]<=target)
{
if(i != begin && candidates[i] == candidates[i-1]) //去重複 //整個一輪返回來,當i = 1, 就會去重複了 稍微有點繞
continue;
tmp.push_back(candidates[i]);
combinationSumCore(res, candidates, target, tmp, sum+candidates[i], i + 1);
tmp.pop_back(); //一層一層返回,一直到第一層 i = begin + 1;
}
else
break;
}
}
}
};
3.https://leetcode-cn.com/problems/word-search/
class Solution {
public:
int n, m;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
bool exist(vector<vector<char>>& board, string word)
{
if(board.empty() || board[0].empty())
return false;
n = board.size(), m = board[0].size();
for(int i = 0; i < n; i++)
{
for(int j = 0; j < m; j++)
{
if(dfs(board, word, i, j, 0)) //false 就繼續試下一個點
return true;
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string& word, int x, int y, int u)
{
if(board[x][y] != word[u])
return false;
if(u == word.size() - 1)
return true;
board[x][y] = '.'; //不能繼續探索到當前點,只有三個方向
for(int i = 0; i < 4; i++)
{
int a = x + dx[i];
int b = y + dy[i];
if(a >= 0 && a < n && b >= 0 && b < m) //判斷下一個探索的點是否合法
if(dfs(board, word, a, b, u+1))
return true;
}
board[x][y] = word[u]; //回朔,回到這個點
return false;
}
};