Leetcode 热题100 回溯
<按出题频率排列>
大佬回溯算法详解:
22. 括号生成
解题思路:
如下
/*
递归每一种字符串加入即可
左右括号数量至少有一个不为0,这种情况下只有左括号能为0,右括号必不可能为0,因为最后一个括号一定是右括号
*/
class Solution {
public:
void addParenthesis(vector<string>& coll, string s, int l, int r){
if(l == 0 && r == 0){
coll.push_back(s);
return;
}
if(l == 0){
addParenthesis(coll, s + ")", l, r - 1);
}
else if(l < r){
addParenthesis(coll, s + "(", l - 1, r);
addParenthesis(coll, s + ")", l, r - 1);
}
else if(l == r){
addParenthesis(coll, s + "(", l - 1, r);
}
}
vector<string> generateParenthesis(int n) {
string s;
vector<string> res;
addParenthesis(res, s, n, n);
return res;
}
};
46. 全排列
解题思路:
见顶部回溯算法详解
class Solution {
public:
//depth表示树的总深度,idex表示当前深度
void dfs(vector<vector<int>> &res, vector<int> &used, vector<int> &nums, vector<int> &s, int &depth, int idex){
if(depth < idex) res.push_back(s);
for(int i = 0; i < depth; i++){
if(used[i] == 0){
s.push_back(nums[i]);
used[i] = 1;//标记已经使用
dfs(res, used, nums, s, depth, idex + 1);
s.erase(s.end() - 1);
used[i] = 0;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
vector<int> s;
int depth = nums.size();
if(depth == 0) return res;
vector<int> used(depth, 0);//状态标记数组
dfs(res, used, nums, s, depth, 1);
return res;
}
};
39. 组合总和
解题思路:
如下
/*
回溯 + 贪心
step1:
将给定数组进行排序
step2:
先一直加入当前位置最大值,直至等于target或者超过target
step2.1: 等于target: 加入该种情况,将该数字标记为已使用(即pos + 1, 到下一个比当前值小的值),返回上一级
step2.2: 大于target: 将数字标记为已使用,返回上一级
*/
class Solution {
public:
void dfs(vector<vector<int>>& res, vector<int>& candidates, int& pos, vector<int>& s, int target, int& sum){
if(sum == target){
res.push_back(s);
return;
}
else if(sum > target) return;
//保存传入位置,离开此次循环时需要重置回初始环境
int tmp = pos;
for(int i = pos; i < candidates.size(); i++){
s.push_back(candidates[i]);
dfs(res, candidates, pos, s, target, sum += candidates[i]);
pos++;
s.erase(s.end() - 1);
sum -= candidates[i];
}
//重置为初始环境
pos = tmp;
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> s;
sort(candidates.begin(), candidates.end(), greater<int>());
int sum = 0, pos = 0;
dfs(res, candidates, pos, s, target, sum);
return res;
}
};
17. 电话号码的字母组合
解题思路:
很简单的回溯算法思路
/*
回溯算法即可,很简单的一道题
*/
class Solution {
public:
vector<string> al = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
void dfs(vector<string>& res, string& digits, int posOfDig, int posInside,string& s){
if(posOfDig == digits.size()){
res.push_back(s);
return;
}
int num = digits[posOfDig] - '0';
int digSize = al[num - 2].size();
for(int i = posInside; i < digSize; i++){
s.push_back(al[num - 2][i]);
if(posOfDig < digits.size()){
dfs(res, digits, posOfDig + 1, 0, s);
}
s.erase(s.end() - 1);
}
}
vector<string> letterCombinations(string digits) {
vector<string> res;
if(digits.size() == 0) return res;
string s;
dfs(res, digits, 0, 0, s);
return res;
}
};
301. 删除无效的括号
HARD: SKIP
78. 子集
解题思路:
如下
//包含所有无序的版本
class Solution {
public:
void dfs(vector<vector<int>>& res, vector<int>& nums, vector<int>& used, vector<int>& add){
if(add.size() == nums.size()) return;
for(int i = 0; i < nums.size(); i++){
if(used[i] == 0){
add.push_back(nums[i]);
res.push_back(add);
used[i] = 1;
dfs(res, nums, used, add);
used[i] = 0;
add.erase(add.end() - 1);
}
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> empty;
res.push_back(empty);
vector<int> used(nums.size(), 0);
vector<int> add;
dfs(res, nums, used, add);
return res;
}
};
//顺序版本
class Solution {
public:
void dfs(vector<vector<int>>& res, vector<int>& nums, int& pos, vector<int>& add){
if(pos == nums.size()) return;
int tmp = pos;
for(int i = pos; i < nums.size(); i++){
add.push_back(nums[i]);
res.push_back(add);
dfs(res, nums, pos += 1, add);
add.erase(add.end() - 1);
}
pos = tmp;
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> empty;
res.push_back(empty);
vector<int> add;
int pos = 0;
dfs(res, nums, pos, add);
return res;
}
};
79. 单词搜索
解题思路:
class Solution {
public:
bool dfsCheck(vector<vector<char>>& board, string& word, int posOfWord, vector<vector<int>>& used, int x, int y){
//检测数组越界
if(x < 0 || x == board.size() || y < 0 || y == board[0].size()) return false;
//检测对应字母是否已经被使用或者不正确
if(used[x][y] == 1 || board[x][y] != word[posOfWord]) return false;
used[x][y] = 1;
//检测是否到了最后一位
if(posOfWord == word.size() - 1) return true;
bool ret = dfsCheck(board, word, posOfWord + 1, used, x - 1, y)
|| dfsCheck(board, word, posOfWord + 1, used, x + 1, y)
|| dfsCheck(board, word, posOfWord + 1, used, x, y - 1)
|| dfsCheck(board, word, posOfWord + 1, used, x, y + 1);
if(!ret) used[x][y] = 0;
return ret;
}
bool exist(vector<vector<char>>& board, string word) {
vector<int> tmp(board[0].size(), 0);
vector<vector<int>> used(board.size(), tmp);//设置标记
int num1 = board.size();
int num2 = board[0].size();
for(int i = 0; i < board.size(); i++){
for(int j = 0; j < board[0].size(); j++){
if(dfsCheck(board, word, 0, used, i, j)) return true;
}
}
return false;
}
};
494. 目标和
解题思路:
回溯非最优思路
class Solution {
public:
//若为减号,mul为-1,若为加号,mul为+1
//sum为表达式的和
//count为满足要求的数量
void dfs(vector<int>& nums, int& target, int sum, int posOfNums, int mul, int& count){
sum += mul * nums[posOfNums];
if(posOfNums == nums.size() - 1){
if(sum == target) count++;
return;
}
dfs(nums, target, sum, posOfNums + 1, 1, count);
dfs(nums, target, sum, posOfNums + 1, -1, count);
}
int findTargetSumWays(vector<int>& nums, int target) {
int count = 0;
dfs(nums, target, 0, 0, 1, count);
dfs(nums, target, 0, 0, -1, count);
return count;
}
};
动态规划思路: