给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
class Solution {
private:
const string letterMap[8] ={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector ret;
public:
//此时s中保存了digits[0,1,...,index-1]翻译到的字符串
//寻找digits[index]匹配的字母,获得digits[0,1,...,index]翻译到的字符串
void combination(const string &digits, int index, string s)
{
if(index == digits.size())
{
ret.push_back(s);
return;
}
string letter = letterMap[digits[index] - '2'];
for(int i = 0; i < letter.size(); i++)
{
combination(digits, index+1, s+letter[i]);
}
return;
}
vector letterCombinations(string digits) {
if(digits.size() == 0)
return ret;
combination(digits, 0, "");
return ret;
}
};
加入调试信息,查看回溯过程。
#include
#include
#include
#include
using namespace std;
class Solution {
private:
const string letterMap[8] ={"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
vector ret;
public:
//此时s中保存了digits[0,1,...,index-1]翻译到的字符串
//寻找digits[index]匹配的字母,获得digits[0,1,...,index]翻译到的字符串
void combination(const string &digits, int index, string s)
{
cout< letterCombinations(string digits) {
if(digits.size() == 0)
return ret;
combination(digits, 0, "");
return ret;
}
};
int main()
{
Solution solve;
string digits;
cin>>digits;
vector ret = solve.letterCombinations(digits);
for(int i = 0; i < ret.size(); i++)
{
cout<
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
示例:
输入: "25525511135"
输出: ["255.255.11.135", "255.255.111.35"]
class Solution {
private:
vector ret;
public:
bool isValid(string s)
{
if(s.size() > 1 && s[0] == '0')
return false;
int ret = atoi(s.c_str());
if(ret > 255)
return false;
return true;
}
void helper(const string &s, int index, int count, string temp)
{
if(count == 0)
{
if(index == s.length())
ret.push_back(temp);
return;
}
for(int i = 1; i <= 3; i++)
{
if(s.length() >= index+i)//不能超过字符串长度
{
string t = s.substr(index, i);
if(!isValid(t))//判断取的数据是否合理,不能大于255,也不能是00,000
continue;
if(count == 1)
helper(s, index+i, count-1, temp+t);
else
helper(s, index+i, count-1, temp+t+".");
}
}
return;
}
vector restoreIpAddresses(string s) {
if(s.length() == 0)
return ret;
helper(s, 0, 4, "");
return ret;
}
};
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab"
输出:
[
["aa","b"],
["a","a","b"]
]
class Solution {
private:
vector> ret;
public:
vector> partition(string s) {
vector temp;
DFS(s, temp, 0);
return ret;
}
void DFS(string s, vector &temp, int pos)
{
if(s.size() == pos)
{
ret.push_back(temp);
return;
}
for(int i = pos; i
给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
class Solution {
private:
vector >ret;
vector used;
public:
//p中保存了index个元素的排列组合
//向其中添加第index+1个元素的排列组合
void helper(const vector &num, int index, vector p)
{
if(index == num.size())
{
ret.push_back(p);
return;
}
for(int i = 0; i < num.size(); i++)
{
if(!used[i])
{
p.push_back(num[i]);
used[i] = true;
helper(num, index+1, p);
p.pop_back();
used[i] = false;
}
}
return;
}
vector> permute(vector& nums) {
if(nums.size() == 0)
return ret;
used = vector(nums.size(), false);
vector p;
helper(nums, 0, p);
return ret;
}
};
类似第31题,寻找下一个排列,将所有排列的情况保存起来。
下一个排列的方法:对当前排列从后向前扫描,找到一对为升序的相邻元素,记为i和j(i < j)。如果不存在这样一对为升序的相邻元素,则序列逆序排列,直接逆转序列,算法结束;否则,重新对当前排列从后向前扫描,找到第一个大于i的元素k,交换i和k,然后对从j开始到结束的子序列反转,则此时得到的新排列就为下一个字典序排列。
class Solution {
public:
vector > permute(vector& nums)
{
sort(nums.begin(),nums.end());
vector >result;
result.push_back(nums);
int i,j;
while(1)
{
for(i=nums.size()-1;i>0;i--)
{
if(nums[i]>nums[i-1])
break;
}
if(i==0)
break;
for(j=nums.size()-1;j>=i;j--)
{
if(nums[j]>nums[i-1])
{
swap(nums[j],nums[i-1]);
break;
}
}
reverse(nums.begin()+i,nums.end());
result.push_back(nums);
}
return result;
}
};
给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2]
输出:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
class Solution {
private:
vector >ret;
public:
void helper(vector num, int index, vector p)
{
if(index == num.size())
{
ret.push_back(p);
return;
}
for(int i = 0; i < num.size(); i++)
{
int c1 = 0, c2 = 0;
if(!i || num[i] != num[i-1])//去除掉重复的情况
{
for(int j = 0; j < p.size(); j++)
{
if(num[i] == p[j])
c1++;
}
for(int j = 0; j < num.size(); j++)
{
if(num[i] == num[j])
c2++;
}
if(c1 < c2)//保证p中的num[i]的个数小于数组中num[i]的个数
{
p.push_back(num[i]);
helper(num, index+1, p);
p.pop_back();
}
}
}
return;
}
vector> permuteUnique(vector& nums) {
if(nums.size() == 0)
return ret;
vector p;
sort(nums.begin(), nums.end());
helper(nums, 0, p);
return ret;
}
};
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
class Solution {
private:
vector> ret;
//求解C(n, k), 当前已找到的组合存储在temp中,从start开始添加新的元素
void helper(int n, int k, int start, vector temp)
{
if(temp.size() == k)
{
ret.push_back(temp);
return;
}
for(int i = start; i <= n ; i++)
{
temp.push_back(i);
helper(n, k, i+1, temp);
temp.pop_back();
}
return;
}
public:
vector> combine(int n, int k) {
if(n == 0 || k == 0 || k > n)
return ret;
vector temp;
helper(n, k, 1, temp);
return ret;
}
};
class Solution {
private:
vector> ret;
//求解C(n, k), 当前已找到的组合存储在temp中,从start开始添加新的元素
void helper(int n, int k, int start, vector temp)
{
if(temp.size() == k)
{
ret.push_back(temp);
return;
}
//已添加元素的个数为temp.size(), 在[i,...,n]范围内至少还需要添加k - temp.size()个元素
//i的最大值为n-(k-temp.size()) +1
for(int i = start; i <= n-(k-temp.size()) +1 ; i++)
{
temp.push_back(i);
helper(n, k, i+1, temp);
temp.pop_back();
}
return;
}
public:
vector> combine(int n, int k) {
if(n == 0 || k == 0 || k > n)
return ret;
vector temp;
helper(n, k, 1, temp);
return ret;
}
};
给定一个无重复元素的数组 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]
]
与上一题组合的不同之处在于,循环里面递归调用回溯函数中的start参数使用i而非i+1,因为题中允许存在重复元素
class Solution {
private:
vector> ret;
void helper(vector& candidates, vector temp, int target, int start)
{
if(target <= 0)
{
if(target == 0)
ret.push_back(temp);
return;
}
for(int i = level; i < candidates.size(); i++)
{
temp.push_back(candidates[i]);
helper(candidates, temp, target - candidates[i], i);
temp.pop_back();
}
return;
}
public:
vector> combinationSum(vector& candidates, int target) {
vector temp;
helper(candidates, temp, target, 0);
return ret;
}
};
给定一个数组 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]
]
这里每个数字只能出现一次,因此start的值是i+1不是i
class Solution {
private:
vector> ret;
void helper(vector& candidates, int target, vector temp, int start)
{
if(target <= 0)
{
if(target == 0)
ret.push_back(temp);
return;
}
for(int i = start; i < candidates.size(); i++)
{
if(i != start && candidates[i] == candidates[i-1])//1,1开头,排除第二个1,跟前面的结果重复了
continue;
target = target - candidates[i];
temp.push_back(candidates[i]);
helper(candidates, target, temp, i+1);
temp.pop_back();
target = target + candidates[i];
}
return;
}
public:
vector> combinationSum2(vector& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector temp;
helper(candidates, target, temp, 0);
return ret;
}
};
找出所有相加之和为 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 {
private:
vector> ret;
void helper(int k, int n, vector temp, int start)
{
if(n <= 0)
{
if(n == 0 && k == 0)
ret.push_back(temp);
return;
}
for(int i = start; i <= 9; i++)
{
temp.push_back(i);
helper(k - 1, n - i, temp, i+1);
temp.pop_back();
}
return;
}
public:
vector> combinationSum3(int k, int n) {
if(k > n)
return ret;
vector temp;
helper(k, n, temp, 1);
return ret;
}
};
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
class Solution {
private:
vector> ret;
void helper(vector nums, int count, int start, vector temp)
{
if(temp.size() == count)
{
ret.push_back(temp);
return;
}
for(int i = start; i < nums.size(); i++)
{
temp.push_back(nums[i]);
helper(nums, count, i+1, temp);
temp.pop_back();
}
return;
}
public:
vector> subsets(vector& nums) {
vector temp;
ret.push_back(temp);
for(int i = 1; i <= nums.size(); i++)
helper(nums, i, 0, temp);
return ret;
}
};
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
class Solution {
private:
vector> ret;
void helper(vector nums, int count, int start, vector temp)
{
if(temp.size() == count)
{
ret.push_back(temp);
return;
}
for(int i = start; i < nums.size(); i++)
{
if(i!=start && nums[i] == nums[i-1])
continue;
temp.push_back(nums[i]);
helper(nums, count, i+1, temp);
temp.pop_back();
}
return;
}
public:
vector> subsetsWithDup(vector& nums) {
vector temp;
ret.push_back(temp);
sort(nums.begin(), nums.end());
for(int i = 1; i <= nums.size(); i++)
helper(nums, i, 0, temp);
return ret;
}
};
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
给定 word = "ABCCED", 返回 true.
给定 word = "SEE", 返回 true.
给定 word = "ABCB", 返回 false.
class Solution {
private:
int dir[4][2] = {{-1,0}, {1, 0}, {0, -1}, {0, 1}};
vector >visit;
bool search(vector>& board, string word, int index, int x, int y)
{
if(index == word.size() - 1)
return word[index] == board[x][y];
if(board[x][y] == word[index])
{
visit[x][y] = true;
for(int i = 0; i < 4; i++)
{
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if(newx < 0 || newx >= board.size() || newy < 0 || newy >= board[0].size() || visit[newx][newy])
continue;
if(search(board, word, index+1, newx, newy))
return true;
}
visit[x][y] = false;
}
return false;
}
public:
bool exist(vector>& board, string word) {
int m = board.size();
int n = board[0].size();
if(m == 0 || word.length() == 0)
return false;
visit = vector>(m, vector(n, false));
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
if(search(board, word, 0, i, j))
return true;
return false;
}
};
给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
class Solution {
private:
int dir[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
public:
int numIslands(vector>& grid) {
if(grid.empty() || grid[0].empty())
return 0;
int m = grid.size(), n = grid[0].size();
int res = 0;
vector >visit(m, vector(n, false));
for(int i = 0;i < m;i++)
for(int j = 0; j < n;j++)
{
if(grid[i][j] == '1' && !visit[i][j])
{
numIslandsDFS(grid, visit, i, j);
res++;
}
}
return res;
}
void numIslandsDFS(vector>& grid, vector >&visit, int x, int y)
{
visit[x][y] = true;
for(int i = 0; i < 4; i++)
{
int newx = x + dir[i][0];
int newy = y + dir[i][1];
if(newx < 0 || newx >= grid.size() || newy < 0 || newy >= grid[0].size() || visit[newx][newy])
continue;
if(grid[newx][newy] == '1')
numIslandsDFS(grid, visit, newx, newy);
}
return ;
}
};
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
class Solution {
private:
vector> ret;
vectorcol;
vectordiag1;
vectordiag2;
vector generate(int n, vector pos)
{
vector res;
for(int i = 0; i < n; i++)
{
string temp = "";
for(int j = 0; j < n; j++)
{
if(j != pos[i])
temp = temp + ".";
else
temp = temp + "Q";
}
res.push_back(temp);
}
return res;
}
void search(int n, int row, vector pos)
{
if(row == n)
{
vector temp = generate(n, pos);
ret.push_back(temp);
return;
}
for(int i = 0; i < n; i++)
{
if(!col[i] && !diag1[row+i] && !diag2[row-i+n-1])
{
col[i] = true;
diag1[row+i] = true;
diag2[row-i+n-1] = true;
pos.push_back(i);
search(n, row+1, pos);
col[i] = false;
diag1[row+i] = false;
diag2[row-i+n-1] = false;
pos.pop_back();
}
}
return;
}
public:
vector> solveNQueens(int n) {
if(n < 1)
return ret;
vector pos;
col = vector(n, false);
diag1 = vector(2*n-1, false);
diag2 = vector(2*n-1, false);
search(n, 0, pos);
return ret;
}
};
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回 n 皇后不同的解决方案的数量。
示例:
输入: 4
输出: 2
解释: 4 皇后问题存在如下两个不同的解法。
[
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
class Solution {
private:
int count;
vectorcol;
vectordiag1;
vectordiag2;
void search(int n, int row)
{
if(row == n)
{
count++;
return;
}
for(int i = 0; i < n; i++)
{
if(!col[i] && !diag1[row+i] && !diag2[row-i+n-1])
{
col[i] = true;
diag1[row+i] = true;
diag2[row-i+n-1] = true;
search(n, row+1);
col[i] = false;
diag1[row+i] = false;
diag2[row-i+n-1] = false;
}
}
return;
}
public:
int totalNQueens(int n) {
if(n < 1)
return 0;
count = 0;
col = vector(n, false);
diag1 = vector(2*n-1, false);
diag2 = vector(2*n-1, false);
search(n, 0);
return count;
}
};
编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
一个数独。
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 '.' 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。
class Solution {
private:
bool check(vector>& board, int i, int j, char c)
{
//行没有重复元素
for(int x = 0; x < 9; x++)
if(board[x][j] == c)
return false;
//列没有重复元素
for(int y = 0; y < 9; y++)
if(board[i][y] == c)
return false;
//九宫格没有重复元素
int row = i - i%3;
int col = j - j%3;
for(int x = 0; x < 3; x++)
for(int y = 0; y < 3; y++)
{
if(board[row+x][col+y] == c)
return false;
}
return true;
}
bool solve(vector>& board, int i, int j)
{
if(i == 9)
return true;
if(j == 9)
return solve(board, i+1, 0);
if(board[i][j] != '.')
return solve(board, i, j+1);
for(char c = '1'; c <= '9'; c++)
{
if(check(board, i, j, c))
{
board[i][j] = c;
if(solve(board, i, j+1))
return true;
board[i][j] = '.';
}
}
return false;
}
public:
void solveSudoku(vector>& board) {
solve(board, 0, 0);
}
};