给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
链接:https://leetcode-cn.com/problems/combinations/
/* 基本思想:回溯算法,相当于深度优先搜索组合
*/
class Solution {
public:
void huisu(vector<vector<int>> &res,vector<int> &cur,int n, int k,int start)
{
if(cur.size()==k)
{
// cout<<"==2"<<endl;
res.push_back(cur);
}
else{
for(int i=start;i<=n;i++)
{
//cout<<i<<endl;
cur.push_back(i);
huisu(res,cur,n,k,i+1);
cur.pop_back();
}
}
}
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> cur;
huisu(res,cur,n,k,1);
return res;
}
};
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
链接:https://leetcode-cn.com/problems/word-search
/*基本思想:深度搜索递归的思想,先找到第一个与word[0]相同的位置,然后调用dfs,在dfs中从当前位置和word当前匹配的情况下上下左右进行搜索word的下一个字符
不一致返回false,注意要确定标志位,是否这个已经访问过,访问过返回false,没访问设定访问,继续dfs,上下左右dfs结束之后,倒回去所以这一位也就再设置为没有访问了
*/
class Solution {
public:
bool dfs(vector<vector<char>>&board, int start_i,int start_j,string word,int word_index,vector<vector<int>> &visited)
{
if(word_index == word.size())
return true;
if(start_i<0 || start_j<0 || start_i>=board.size() || start_j>=board[start_i].size()||board[start_i][start_j]!=word[word_index])
return false;
if(visited[start_i][start_j]==1)
return false;
visited[start_i][start_j]=1;
bool res = dfs(board,start_i+1,start_j,word,word_index+1,visited)||dfs(board,start_i,start_j+1,word,word_index+1,visited)
|| dfs(board,start_i-1,start_j,word,word_index+1,visited)||dfs(board,start_i,start_j-1,word,word_index+1,visited);
visited[start_i][start_j]=0;
return res;
}
bool exist(vector<vector<char>>& board, string word) {
vector<vector<int>> visited(board.size(),vector<int>(board[0].size(),0));
int i,j;
for(i=0;i<board.size();i++)
{
for(j=0;j<board[i].size();j++)
{
if(board[i][j] == word[0])
if( dfs(board,i,j,word,0,visited))
return true;
}
}
return false;
}
};
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
链接:https://leetcode-cn.com/problems/combination-sum
/*基本思想:就是回溯的思想,因为要升序排列,且结果集合不允许重复,所以先把原始数组排序,回溯的时候循环不让他往回找,一直向后找即可
*/
class Solution {
public:
void dfs(vector<int>& candidates,vector<int> &cur,vector<vector<int>> &res,int sum,int target,int index)
{
int i;
if(sum == target)
{
res.push_back(cur);
return;
}
else if(sum >target)
return;
else{
for(i=index;i<candidates.size();i++)
{
sum+=candidates[i];
cur.push_back(candidates[i]);
dfs(candidates,cur,res,sum,target,i);
sum-=candidates[i];
cur.pop_back();
}
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> cur;
int sum = 0;
vector<vector<int>> res;
sort(candidates.begin(),candidates.end());
dfs(candidates,cur,res,sum,target,0);
return res;
}
};
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
链接:https://leetcode-cn.com/problems/combination-sum-ii
/*基本思想:还是回溯,只是注意去重,去重有两种方法,一种是利用set去重,还有一种是在每一层选数字的时候,判断和前一个相同就跳过
*/
class Solution {
public:
/*void dfs(vector<int> &candidates, vector<int> &cur,int target,int index,int sum,set<vector<int>>&res)
{
if(sum == target)
{
res.insert(cur);
return;
}
else if(target < sum)
return ;
else{
for(int i=index;i<candidates.size();i++)
{
cur.push_back(candidates[i]);
sum+=candidates[i];
dfs(candidates,cur,target,i+1,sum,res);
sum-=candidates[i];
cur.pop_back();
}
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<int> cur;
set<vector<int>> res;
set<vector<int>>::iterator iter;
int sum=0;
dfs(candidates,cur,target,0,sum,res);
vector<vector<int>> result;
for(iter=res.begin();iter!=res.end();iter++)
{
result.push_back(*iter);
}
return result;
}
*/
void dfs(vector<int> &candidates, vector<int> &cur,int target,int index,int sum,vector<vector<int>>&res)
{
if(sum == target)
{
res.push_back(cur);
return;
}
else if(target < sum)
return ;
else{
for(int i=index;i<candidates.size();i++)
{
if(i>index && candidates[i] == candidates[i-1]) //同一层选的时候去重
continue;
cur.push_back(candidates[i]);
sum+=candidates[i];
dfs(candidates,cur,target,i+1,sum,res);
sum-=candidates[i];
cur.pop_back();
}
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<int> cur;
vector<vector<int>> res;
int sum=0;
dfs(candidates,cur,target,0,sum,res);
return res;
}
};
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
链接:https://leetcode-cn.com/problems/restore-ip-addresses/
/*基本思想: 深度优先搜索,每次取不超过3个数字去判断,满足,就连接,记录一个总数,如果总数是4,组成一个ip,写入result,否则继续,此处有一个剪枝操作,count>4 剪枝,不需要再继续了,否则可能会出现超时现象
注意判断数字是否合法,用stoi时进行异常处理一下,可能字符串超出int范围
*/
class Solution {
public:
void dfs(vector<string> &result, string pre,string s,int count)
{
if(count==4 && isvaild(s))
{
result.push_back(pre+s);
}
if(count>4) //剪枝操作
return;
for(int i=1;i<4 && i<s.size();i++)
{
string cur = s.substr(0,i);
string rest = s.substr(i);
if(isvaild(cur))
{
dfs(result,pre+cur+'.',rest,count+1);
}
}
}
bool isvaild(string s)
{
if(s.size()>1 && s[0]=='0')
return false;
int num;
try {
num=stoi(s);
}
catch (std::out_of_range&){
return false;
}
if(num>=0 && num<=255)
return true;
return false;
}
vector<string> restoreIpAddresses(string s) {
string pre;
vector<string> result;
dfs(result,pre,s,1);
return result;
}
};
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
链接:https://leetcode-cn.com/problems/n-queens
/*基本思想:回溯,主要是判断冲突的时候,同行,同列,两条对角线都不能冲突
(其实check里面不用检查同行的冲突,我们就是按照行放置的,放置一个就到下一行,所以不会冲突)
*/
class Solution {
public:
bool check(int curRow, int col,vector<string> &curRes)
{
for(int i=0;i<curRow;i++)
if(curRes[i][col] == 'Q')
return false;
for (int i = curRow - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) {
if (curRes[i][j] == 'Q') return false;
}
for (int i = curRow - 1, j = col + 1; i >= 0 && j < curRes.size(); --i, ++j) {
if (curRes[i][j] == 'Q') return false;
}
return true;
}
void solve(vector<vector<string>> &res, vector<string> &curRes,int curRow,int n)
{
if(curRow == n)
{
res.push_back(curRes);
return;
}
for(int i=0;i<n;i++)
{
curRes[curRow][i]='Q';
if(check(curRow,i,curRes))
{
solve(res,curRes,curRow+1,n);
}
curRes[curRow][i]='.';
}
}
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<string> curRes(n,string(n, '.'));
solve(res,curRes,0,n);
return res;
}
};
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
链接:https://leetcode-cn.com/problems/n-queens-ii/
/* 基本思想: 和n皇后的问题一样,只不过不需要输出排列,只需要累加数量就好
*/
class Solution {
public:
bool check(int curRow, int col,vector<string> &curRes)
{
for(int i=0;i<curRow;i++)
if(curRes[i][col] == 'Q')
return false;
for (int i = curRow - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) {
if (curRes[i][j] == 'Q') return false;
}
for (int i = curRow - 1, j = col + 1; i >= 0 && j < curRes.size(); --i, ++j) {
if (curRes[i][j] == 'Q') return false;
}
return true;
}
void solve(vector<string> &curRes,int curRow,int n)
{
if(curRow == n)
{
sum++;
return;
}
for(int i=0;i<n;i++)
{
curRes[curRow][i]='Q';
if(check(curRow,i,curRes))
{
solve(curRes,curRow+1,n);
}
curRes[curRow][i]='.';
}
}
int sum=0;
int totalNQueens(int n) {
vector<string> curRes(n,string(n, '.'));
solve(curRes,0,n);
return sum;
}
};
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
链接:https://leetcode-cn.com/problems/generate-parentheses/
/*基本思想: 就是回溯递归,添加左右括号,一共要添加n个左括号和n个右括号,先添加左括号,一直递归,添加了n个,然后添加右括号,之后回溯,添加右括号,找到所有匹配结果*/
class Solution {
public:
void generate(int usedLeft,int usedRight, string s, vector<string> &result,int n)
{
if(usedLeft == n && usedRight == n)
{
result.push_back(s);
return;
}
if(usedLeft < n)
{
generate(usedLeft + 1, usedRight, s + "(", result,n);
}
if(usedRight < n && usedLeft > usedRight)
{
generate(usedLeft, usedRight + 1, s + ")", result,n);
}
}
vector<string> generateParenthesis(int n) {
vector<string> result;
generate(0, 0, "", result,n);
return result;
}
};