1,组合
77. 组合 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combine(int n, int k) {
dfs(n, k, 1);
return res;
}
//n表示从1-n里面选,k表示要选多少个数,start表示选择的起点
void dfs(int n, int k, int start) {
//剪枝,如果path加上起点到终点的长度还是小于k的话,不可能构造成功
if (path.size() + n - start + 1 < k) return;
if (path.size() == k) {
res.push_back(path);
return;
}
for (int i = start; i <= n; i++) {
path.push_back(i);
dfs(n, k, i + 1);
path.pop_back();
}
}
};
17. 电话号码的字母组合 - 力扣(LeetCode)
class Solution {
public:
vector<string> res;
//每个数字的组合情况
string strs[10] = {
" ", " ", "abc",
"def", "ghi", "jkl",
"mno", "pqrs", "tuv",
"wxyz"};
vector<string> letterCombinations(string digits) {
if (digits.empty()) return res;
dfs(digits, 0, "");
return res;
}
//u表示当前第几位,path表示当前的路径
void dfs(string digits, int u, string path) {
if (u == digits.size()) res.push_back(path);
else {
//遍历这一位可以取哪些字符
for (auto str : strs[digits[u] - '0']) {
dfs(digits, u + 1, path + str);
}
}
}
};
39. 组合总和 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum(vector<int>& c, int t) {
dfs(c, 0, t);
return res;
}
//u表示当前枚举到第几个数,t表示还差多少
void dfs(vector<int> &c, int u, int t) {
if (!t) {
res.push_back(path);
return;
}
if (u == c.size()) return;
//枚举当前的数选几个
for (int i = 0; i * c[u] <= t; i++) {
dfs(c, u + 1, t - i * c[u]);
path.push_back(c[u]);
}
//恢复现场
for (int i = 0; i * c[u] <= t; i++)
path.pop_back();
}
};
40. 组合总和 II - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum2(vector<int>& c, int t) {
//排序,为了方便统计重复数字的个数
sort(c.begin(), c.end());
dfs(c, 0, t);
return res;
}
//u表示当前枚举到第几个数,t表示还剩多少
void dfs(vector<int> &c, int u, int t) {
if (!t) {
res.push_back(path);
return;
}
if (u == c.size()) return;
int k = u + 1;
while (k < c.size() && c[k] == c[u]) k++;
//统计个数
int cnt = k - u;
for (int i = 0; i * c[u] <= t && i <= cnt; i++) {
dfs(c, k, t - i * c[u]);
path.push_back(c[u]);
}
//恢复现场
for (int i = 0; i * c[u] <= t && i <= cnt; i++)
path.pop_back();
}
};
216. 组合总和 III - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum3(int k, int n) {
dfs(1, n, k);
return res;
}
//u表示当前是第几个数,n表示还差多少,k表示还剩的个数
void dfs(int u, int n, int k) {
//如果当前和已经等于n
if (!n) {
//如果恰好是k个数
if (!k) res.push_back(path);
//当前和没有到n,个数也没有到k
} else if (k) {
//当前数从u开始选
for (int i = u; i <= 9; i++) {
//如果当前数小于等于n
if (n >= i) {
//选i
path.push_back(i);
//枚举下一个数
dfs(i + 1, n - i, k - 1);
//恢复现场
path.pop_back();
}
}
}
}
};
2,分割
131. 分割回文串 - 力扣(LeetCode)
class Solution {
public:
vector<vector<bool>> f;
vector<vector<string>> res;
vector<string> path;
vector<vector<string>> partition(string s) {
int n = s.size();
//f[i][j]表示i~j是回文串
f = vector<vector<bool>> (n, vector<bool> (n));
for (int j = 0; j < n; j++)
for (int i = 0; i <= j; i++) {
//如果只有一个字符,是回文串
if (i == j) f[i][j] = true;
else if (s[i] == s[j]) {
//如果是两个字符或者i+1~j-1是回文串,i~j就也是回文串
if (i + 1 > j - 1 || f[i + 1][j - 1]) f[i][j] = true;
}
}
//暴搜
dfs(s, 0);
return res;
}
//u表示第几个字符
void dfs(string s, int u) {
if (u == s.size()) {
res.push_back(path);
}
else {
for (int i = u; i < s.size(); i++) {
//如果u~i是回文串,记录,并搜索下一个字母
if (f[u][i]) {
path.push_back(s.substr(u, i - u + 1));
dfs(s, i + 1);
path.pop_back();
}
}
}
}
};
93. 复原 IP 地址 - 力扣(LeetCode)
class Solution {
public:
vector<string> res;
vector<string> restoreIpAddresses(string s) {
dfs(s, 0, 0, "");
return res;
}
//u表示s的第u位,k表示第k个数
void dfs(string& s, int u, int k, string path) {
//如果搜到s的最后一位,并且是第四个数,保存答案
if (u == s.size()) {
if (k == 4) {
path.pop_back();
res.push_back(path);
}
return;
}
//如果超过四个数,直接返回
if (k == 4) return;
//从第u位开始搜,t用来记录数值
for (int i = u, t = 0; i < s.size(); i++) {
//如果有前导零就break
if (i > u && s[u] == '0') break;
t = t * 10 + s[i] - '0';
//如果t在0-255之内就搜下一层
if (t <= 255) {
dfs(s, i + 1, k + 1, path + to_string(t) + '.');
}
//否则,break
else break;
}
}
};
3,子集
78. 子集 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums, 0);
return res;
}
//u表示当前是第几个数
void dfs(vector<int>& nums, int u) {
//因为要记录子集,所以不用等到u==n的时候再加入答案
res.push_back(path);
for (int i = u; i < nums.size(); i++) {
path.push_back(nums[i]);
dfs(nums, i + 1);
path.pop_back();
}
}
};
90. 子集 II - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
dfs(nums, 0);
return res;
}
//u表示当前是第几位
void dfs(vector<int>& nums, int u) {
//如果枚举到最后一位就返回答案
if (u == nums.size()) {
res.push_back(path);
return;
}
int k = u + 1;
//统计重复元素的个数
while (k < nums.size() && nums[u] == nums[k]) k++;
//将重复元素枚举
for (int i = 0; i <= k - u; i++) {
dfs(nums, k);
path.push_back(nums[u]);
}
//恢复现场
for (int i = 0; i <= k - u; i++)
path.pop_back();
}
};
4,排列
46. 全排列 - 力扣(LeetCode)
class Solution {
public:
//记录第i个位置的状态
vector<bool> st;
vector<int> path;
vector<vector<int>> result;
void dfs(vector<int>& nums, int u) {
//如果第u个位置已经等于数组长度,说明列举完了
if (u == nums.size()) {
result.push_back(path);
return;
}
//从第一个位置开始枚举
for (int i = 0; i < nums.size(); i++) {
//如果第i个位置没有放元素
if (!st[i]) {
path[u] = nums[i];
st[i] = true;
dfs(nums, u + 1);
st[i] = false;
path[u] = -1;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
int n = nums.size();
st = vector<bool> (n);
path = vector<int> (n);
dfs(nums, 0);
return result;
}
};
47. 全排列 II - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<bool> st;
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
st = vector<bool>(n);
path = vector<int>(n);
//排序,用来判重
sort(nums.begin(), nums.end());
dfs(nums, 0);
return res;
}
//u表示枚举第几位
void dfs(vector<int>& nums, int u) {
if (u == nums.size()) {
res.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (!st[i]) {
//如果有重复元素,只用第一个
if (i && nums[i] == nums[i - 1] && !st[i - 1]) continue;
path[u] = nums[i];
st[i] = true;
dfs(nums, u + 1);
st[i] = false;
}
}
}
};
5,棋盘问题
51. N 皇后 - 力扣(LeetCode)
class Solution {
public:
vector<bool> col, dg, udg;
vector<vector<string>> res;
vector<string> path;
int n;
vector<vector<string>> solveNQueens(int _n) {
n = _n;
col = vector<bool> (n);
dg = udg = vector<bool> (2 * n);
path = vector<string> (n, string(n, '.'));
dfs(0);
return res;
}
//全排列的思想,u表示第几行
void dfs(int u) {
if (u == n) {
res.push_back(path);
return;
}
for (int i = 0; i < n; i++) {
//如果第i列,对角线,反对角线都没有放置皇后
if (!col[i] && !dg[u - i + n] && !udg[u + i]) {
path[u][i] = 'Q';
col[i] = dg[u - i + n] = udg[u + i] = true;
dfs(u + 1);
col[i] = dg[u - i + n] = udg[u + i] = false;
path[u][i] = '.';
}
}
}
};
37. 解数独 - 力扣(LeetCode)
class Solution {
public:
bool row[9][9], col[9][9], cell[3][3][9];
void solveSudoku(vector<vector<char>>& board) {
memset(row, 0, sizeof row);
memset(col, 0, sizeof col);
memset(cell, 0, sizeof cell);
int n = board.size(), m = board[0].size();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
//如果board[i][j] != '.',记录当前位置为true
if (board[i][j] != '.') {
int t = board[i][j] - '1';
row[i][t] = col[j][t] = cell[i / 3][j / 3][t] = true;
}
}
//从0,0开始搜索
dfs(board, 0, 0);
}
//x表示第几行,y表示第几列
bool dfs(vector<vector<char>>& board, int x, int y) {
//如果这一列搜索完,就搜索下一行
if (y == 9) x++, y = 0;
//如果搜索完,返回true
if (x == 9) return true;
//如果当前值不为'.',搜索下一行
if (board[x][y] != '.') return dfs(board, x, y + 1);
for (int i = 0; i < 9; i++) {
//如果当前行列都没有出现数字
if (!row[x][i] && !col[y][i] && !cell[x / 3][y / 3][i]) {
board[x][y] = '1' + i;
row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = true;
if (dfs(board, x, y + 1)) return true;
board[x][y] = '.';
row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = false;
}
}
return false;
}
};
6,其他
491. 递增子序列 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> findSubsequences(vector<int>& nums) {
dfs(nums, 0);
return res;
}
//st表示当前开始的位置
void dfs(vector<int>& nums, int st) {
//如果path的长度大于等于2,加入答案
if (path.size() >= 2) res.push_back(path);
if (st == nums.size()) return;
//哈希表记录当前数是否已经用过
unordered_set<int> S;
for (int i = st; i < nums.size(); i++) {
//如果path为空,或者当前数大于path的最后一个数,看是否需要加入path
if (path.empty() || nums[i] >= path.back()) {
//如果已经用过,跳过
if (S.count(nums[i])) continue;
//加入哈希表和答案
S.insert(nums[i]);
path.push_back(nums[i]);
//搜索下一个数
dfs(nums, i + 1);
path.pop_back();
}
}
}
};
332. 重新安排行程 - 力扣(LeetCode)
class Solution {
public:
unordered_map<string, multiset<string>> g;
vector<string> ans;
vector<string> findItinerary(vector<vector<string>>& tickets) {
for (auto &t : tickets) g[t[0]].insert(t[1]);
dfs("JFK");
return vector<string>(ans.rbegin(), ans.rend());
}
void dfs(string ver) {
while (g[ver].size()) {
string next = *g[ver].begin();
g[ver].erase(g[ver].begin());
dfs(next);
}
ans.push_back(ver);
}
};