回朔算法的思想很简单,每一步都是尝试,如果正确进行下一步,如果不正确则回退,回退到上一步或者原点。 为了优化时间,不必要的搜索要进行剪枝操作
常见的深度优先搜索就是回朔法的思想,来几道经典的回朔法。
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;
}
};