给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
class Solution {
public:
vector<string> ans;
char ops[10][10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector<string> letterCombinations(string digits) {
dfs(digits, 0, "");
return ans;
}
void dfs(string &digits, int u, string path)
{
if(u == digits.size())
{
if(path.size()) ans.push_back(path);//需判断边界情况
return ; //很重要!!!
}
int v = digits[u] - '0';//当前位
for(int i = 0; ops[v][i]; i++)
{
dfs(digits,u + 1, path + ops[v][i]);
}
}
};
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution {
public:
vector<vector<int>> ans; //答案
vector<int> path;//方案
vector<bool> st;//没有使用过的数字
vector<vector<int>> permute(vector<int>& nums) {
st = vector<bool>(nums.size(), false);//初始化
dfs(nums, 0);
return ans;
}
void dfs(vector<int>& nums, int u)
{
if(u == nums.size())
{
ans.push_back(path);
return;//重要
}
for(int i = 0; i < nums.size(); i++)
if(!st[i])
{
st[i] = true, path.push_back(nums[i]);
dfs(nums, u + 1);
st[i] = false, path.pop_back();//恢复现场
}
}
};
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<bool> st;//该位置有没有被占用
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end()); //从小到大排序
path = vector<int>(nums.size()); //初始化写法
st = vector<bool>(nums.size(), false);
dfs(nums, 0, 0);//第三位 相同元素相对位置
return ans;
}
void dfs(vector<int> &nums, int u, int start)
{
if(u == nums.size())
{
ans.push_back(path);
return;
}
for(int i = start; i < path.size(); i++) //i从start开始循环
{
if(st[i]) continue;//该位置被用过,循环下一位
path[i] = nums[u], st[i] = true;
if(u + 1 < nums.size() && nums[u + 1] == nums[u])
dfs(nums, u + 1, i + 1);//从i+1开始循环保证相对顺序不变
else dfs(nums, u + 1, 0);//没必要调序,则从0开始循环
st[i] = false;
}
}
};
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> ans;
for(int i = 0; i < (1 << n); i++)
{
vector<int> path;
for(int j = 0; j < n; j++) //枚举是不是1
if(i >> j & 1) //判断第j位是不是1
path.push_back(nums[j]);//push nums[j] 是1 push第 j位
ans.push_back(path);
}
return ans;
}
};
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;//当前方案
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
dfs(nums, 0);
return ans;
}
void dfs(vector<int> &nums, int u)
{
if(u == nums.size())
{
ans.push_back(path);
return;
}
int k = u;
while(k < nums.size() && nums[k] == nums[u]) k++;//枚举重复位
dfs(nums, k);//对重复位下一位操作
for(int i = u; i < k; i++) //对重复位操作
{
path.push_back(nums[i]);
dfs(nums, k);
}
//恢复现场
while(path.size() && path.back() == nums[u]) path.pop_back();
}
};
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
dfs(candidates, 0, target);
return ans;
}
void dfs(vector<int>&candidates, int u, int target)
{
if(u == candidates.size())
{
if(!target) ans.push_back(path);//target减为0 记录方案
return;
}
dfs(candidates, u + 1, target);
while(target >= candidates[u])
{
path.push_back(candidates[u]);
target -= candidates[u];
dfs(candidates, u + 1, target);
}
//恢复现场
while(path.size() && path.back() == candidates[u]) path.pop_back();
}
};
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
class Solution {
public:
vector<vector<int>> ans;
vector<int> path;
vector<vector<int>> combinationSum2(vector<int>& a, int target) {
sort(a.begin(), a.end());
dfs(a, path, 0, target);
return ans;
}
void dfs(vector<int>&a, vector<int>&path, int u, int target)
{
if(!target)
{
ans.push_back(path);
return;
}
if(u == a.size()) return; //顺序要在后面
int k = u + 1;
while(k < a.size() && a[k] == a[u]) k++;
dfs(a, path, k, target);
int value = a[u];
for(int i = value, j = u; j < k && i <= target; i += value, j++)
{
path.push_back(value);
dfs(a, path, k, target - i); //从开始下一次循环
}
while(!path.empty() && path.back() == value)
path.pop_back();//恢复现场
}
};
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
class Solution {
public:
vector<vector<int>> ans;
vector<vector<int>> combinationSum3(int k, int n) {
for(int i = 0; i < (1 << 9); i++)//512
{
vector<int> path;
int sum = 0;
for(int j = 0; j < 9; j++)
if(i >> j & 1)
{
path.push_back(j + 1);
sum += j + 1;
}
if(sum == n && path.size() == k)
{
ans.push_back(path);
}
}
return ans;
}
};
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
class Solution {
public:
int m;
vector<string> ans;
vector<string> generateParenthesis(int n) {
m = n;
dfs("", 0, 0);
return ans;
}
void dfs(string path, int l, int r)//左 右 括号数
{
if(l == m && r == m)
{
ans.push_back(path);
return;
}
if(l < m) dfs(path + '(', l + 1, r); //l < m
if(l > r) dfs(path + ')', l, r + 1);
}
};
还记得童话《卖火柴的小女孩》吗?现在,你知道小女孩有多少根火柴,请找出一种能使用所有火柴拼成一个正方形的方法。不能折断火柴,可以把火柴连接起来,并且每根火柴都要用到。
输入为小女孩拥有火柴的数目,每根火柴用其长度表示。输出即为是否能用所有的火柴拼成正方形。
示例 1:
输入: [1,1,2,2,2]
输出: true
解释: 能拼成一个边长为2的正方形,每边两根火柴。
示例 2:
输入: [3,3,3,3,4]
输出: false
解释: 不能用所有火柴拼成一个正方形。
注意:
给定的火柴长度和在 0 到 10^9之间。
火柴数组的长度不超过15。
class Solution {
public:
int side;//每条边长度
vector<bool> st;//每根棍是不是被用
bool makesquare(vector<int>& nums) {
if(nums.empty()) return false;
int sum = 0;
for(auto &x : nums) sum += x;
if(sum % 4) return false;
side = sum / 4;
//先搜大木棍
sort(nums.begin(), nums.end());
st = vector<bool>(nums.size(), false);
return dfs(nums, 0, side, nums.size() - 1);
}
bool dfs(vector<int>&nums, int count, int sum, int start)
{
if(!sum)
{
if( ++ count == 4) return true;
return dfs(nums, count, side, nums.size() - 1);//拼下一个木棍
}
for(int i = start; i >= 0; i --)
if(!st[i] && sum >= nums[i])
{
//剪枝1 上一根木棍失败 当前根与上一根一样 也会失败
if(i + 1 < nums.size() && !st[i + 1] && nums[i + 1] == nums[i]) continue;
st[i] = true;
if(dfs(nums, count, sum - nums[i], i - 1)) return true;//有解返回true
st[i] = false;
//剪枝2 失败的木棍是开头或结尾
if(nums[i] == sum || sum == side) return false;
}
return false;
}
};
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
示例:
输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q…", // 解法 1
“…Q”,
“Q…”,
“…Q.”],
["…Q.", // 解法 2
“Q…”,
“…Q”,
“.Q…”]
]
class Solution {
public:
int ans, n;
vector<bool> col, diag, anti_diag;
int totalNQueens(int _n) {
n = _n;
col = vector<bool>(n, false);
diag = anti_diag = vector<bool>(2 * n, false);
dfs(0); //第0行开始
return ans;
}
void dfs(int u)
{
if(u == n)
{
ans++;
return;
}
for(int i = 0; i < n; i++)
//如何判断是否在对角上呢?正对角就是相加之和一样的,负对角就是相减只差一样的
if(!col[i] && !diag[u + i] && !anti_diag[u - i + n])//会变负数 再加个n
{
col[i] = diag[u + i] = anti_diag[u - i + n] = true;
dfs(u + 1);
col[i] = diag[u + i] = anti_diag[u - i + n] = false;
}
}
};
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
class Solution {
public:
bool row[9][9], col[9][9], sq[3][3][9];//row 第一行 1-9存不存在数字
void solveSudoku(vector<vector<char>>& board) {
memset(row, 0, sizeof row);
memset(col, 0, sizeof col);
memset(sq, 0, sizeof sq);
for(int i = 0; i < 9; i++)
for(int j = 0; j < 9; j++)
if(board[i][j] != '.')
{
int v = board[i][j] - '1';
row[i][v] = col[j][v] = sq[i/3][j/3][v] = true;
}
dfs(board, 0, 0);
}
bool dfs(vector<vector<char>>&board, int x, int y)
{
if(y == 9) y = 0, x++;
if(x == 9) return true;
if(board[x][y] != '.') return dfs(board, x, y + 1);
for(int i = 0; i < 9; i ++)
if(board[x][y] == '.' && !row[x][i] && !col[y][i] && !sq[x/3][y/3][i])
{
board[x][y] = '1' + i;
row[x][i] = col[y][i] = sq[x/3][y/3][i] = true;
if(dfs(board, x, y + 1)) return true;
board[x][y] = '.';
row[x][i] = col[y][i] = sq[x/3][y/3][i] = false;
}
return false;
}
};
给定一个仅包含数字 0-9 的字符串和一个目标值,在数字之间添加二元运算符(不是一元)+、- 或 * ,返回所有能够得到目标值的表达式。
示例 1:
输入: num = “123”, target = 6
输出: [“1+2+3”, “123”]
示例 2:
输入: num = “232”, target = 8
输出: [“23+2", "2+32”]
示例 3:
输入: num = “105”, target = 5
输出: [“1*0+5”,“10-5”]
示例 4:
输入: num = “00”, target = 0
输出: [“0+0”, “0-0”, “0*0”]
示例 5:
输入: num = “3456237490”, target = 9191
输出: []
class Solution {
public:
vector<string> ans;
vector<string> addOperators(string num, int target) {
dfs(num, "", 0, 0, 0, target);//从第0位开始 和为0 积为0
return ans;
}
void dfs(string &num, string path, int pos, long long sum, long long mul, int target)
{
if(pos == num.size())
{
if(sum == target) ans.push_back(path);
return;
}
for(int i = pos; i < num.size(); i++) //从前枚举到最后一位
{
if(i > pos && num[pos] == '0') break;
long long v = 0;
for(int j = pos; j <= i; j++) v = v * 10 + num[j] - '0'; //多位数
string number = num.substr(pos, i - pos + 1);
if(!pos) //当前位是0
{
dfs(num, number, i + 1, v, v, target);
}
else
{
dfs(num, path + '+' + number, i + 1, sum + v, v, target);
dfs(num, path + '-' + number, i + 1, sum - v, -v, target);
dfs(num, path + '*' + number, i + 1, sum - mul + mul * v, mul * v, target);
}
}
}
};
删除最小数量的无效括号,使得输入的字符串有效,返回所有可能的结果。
说明: 输入可能包含了除 ( 和 ) 以外的字符。
示例 1:
输入: “()())()”
输出: ["()()()", “(())()”]
示例 2:
输入: “(a)())()”
输出: ["(a)()()", “(a())()”]
示例 3:
输入: “)(”
输出: [""]
class Solution {
public:
set<string> ans;
vector<string> removeInvalidParentheses(string s) {
int left = 0, right = 0;
for(auto c : s)
if(c == '(')
{
left++;
}
else if(c == ')')
{
if(left) left--;
else right ++;
}
dfs(s, 0, left, right);
return vector<string>(ans.begin(), ans.end());//把所有方案放到set里面判重
}
bool check(string s) //检查左右括号数目是不是相等
{
int cnt = 0;
for(auto c : s)
if(c == '(')
cnt ++;
else if(c == ')')
{
cnt --;
if(cnt < 0) return false;
}
return cnt == 0;
}
void dfs(string s, int u, int left, int right)
{
if(u == s.size())
{
if(check(s)) ans.insert(s); //合法记录答案
return;
}
dfs(s, u + 1, left, right);//不删的情况,枚举下一位
if(left > 0 && s[u] == '(')
{
string rans = s;//备份
s.erase(s.begin() + u);
dfs(s, u, left - 1, right);
s = rans;//恢复现场
}
if(right > 0 && s[u] == ')')
{
string rans = s;//备份
s.erase(s.begin() + u);
dfs(s, u, left, right - 1);
s = rans;//恢复现场
}
}
};