*题目编号为Leetcode中对应的题号。
某位大佬的Leetcode题解参考链接
回溯法
- (17 电话号码的字母组合) 给定一个仅包含数字
2-9
的字符串,返回所有它能表示的字母组合。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:
输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
class Solution {
private:
vector<string> res;
const string letterMap[10]={
" ",// 0
"",// 1
"abc",// 2
"def",// 3
"ghi",// 4
"jkl",// 5
"mno",// 6
"pqrs",// 7
"tuv",// 8
"wxyz"// 9
}
// s存放的是digits[0,index-1]中的数字组成的字母字符串
// 寻找和digits[index]匹配的字母,获得digits[0,index-1]的字母字符串
void findCombination(congst string &digits, int index, const string &s){
if(index==digits.size()){
res.push_back(s);// 这里不用清空s
return;
}
char c=digits[index];
string letters=letterMap['c'-'0'];
for(int i=0;i<letters.size();i++)
findCombination(digits, index+1, s+letters[i]);
return;
public:
vector<string> letterCombinations(string digits) {
res.clear();
if(digits=="")
return res;
findCombination(digits, 0, "")
return res;
}
};
-
(93复原IP地址) 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导
0
),整数之间用'.'
分隔。例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效的 IP 地址。示例:
输入:s = "25525511135" 输出:["255.255.11.135","255.255.111.35"] 输入:s = "101023" 输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
vector<int> ip;
dfs(s, 0, ip, res);
return res;
}
private:
void dfs(const string& s, int index, vector<int>& ip, vector<string>& res){
if(index == s.size()){
if(ip.size() == 4)
res.push_back(get_string(ip));
return;
}
if(index == 0){
ip.push_back(s[0] - '0');
dfs(s, index + 1, ip, res);
}
else{
int next = ip.back() * 10 + (s[index] - '0');
if(next <= 255 && ip.back() != 0){
ip.back() = next;
dfs(s, index + 1, ip, res);
ip.back() /= 10;
}
if(ip.size() < 4){
ip.push_back(s[index] - '0');
dfs(s, index + 1, ip, res);
ip.pop_back();
}
}
}
string get_string(const vector<int>& ip){
string res = to_string(ip[0]);
for(int i = 1; i < ip.size(); i ++)
res += "." + to_string(ip[i]);
return res;
}
};
-
(131分割回文串) 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]
排列问题
- (46 全排列) 给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
// Perms{nums[0,n-1]} = {取出一个数} + Perms{nums[0,n-1]-这个数})
class Solution {
private:
vector<vector<int>> res;
vector<bool> used;
// 对第indexs个数,根据used数组从nums中选择一个数字加入到n中
void generatePermutation(vector<int>& nums, int index, vector<int> &n){
if(index==nums.size()){
res.push_back(n);
return;
}
for(int i=0;i<nums.size();i++){
if(!used[i]){
n.push_back(nums[i]);
used[i]=true;
generatePermutation(nums, index+1, n);
// 状态恢复
n.pop_back();
used[i]=false;
}
}
return;
}
public:
vector<vector<int>> permute(vector<int>& nums) {
res.clear();
if(nums.size()==0)
return res;
used=vector<bool>(nums.size(), false);
vector<int> p;
generatePermutation(nums, 0, p);
return res;
}
};
-
(47全排列II) 给定一个可包含重复数字的序列,返回所有不重复的全排列。
示例:
输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ]
/// Most Naive Recursive
/// Time Complexity: O(n^n)
/// Space Complexity: O(n)
class Solution {
private:
vector<vector<int>> res;
vector<bool> used;
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
res.clear();
if(nums.size() == 0)
return res;
used = vector<bool>(nums.size(), false);
sort(nums.begin(), nums.end());
vector<int> p;
generatePermutation(nums, 0, p);
return res;
}
private:
void generatePermutation(const vector<int>& nums, int index, vector<int> &p){
if(index == nums.size()){
res.push_back(p);
return;
}
for(int i = 0 ; i < nums.size() ; i ++)
if(!used[i]){
if(i > 0 && nums[i] == nums[i-1] && !used[i-1])
continue;
p.push_back(nums[i]);
used[i] = true;
generatePermutation(nums, index + 1, p);
p.pop_back();
used[i] = false;
}
}
};
组合问题
- (77 组合) 给定两个整数 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<vector<int>> res;
// 求解C(n,k) 已经找到的组合存放在c中,从start开始搜索新的元素
void findCombination(int n, int k, int start, vector<int> &c){
if(c.size()==k){
res.push_back(c);
return;
}
// [i,n]中至少要有k-c.size()个元素
for(int i=start;i<=(n-(k-c.size())+1);i++){
// 一步优化
c.push_back(i);
findCombination(n, k, i+1, c);
c.pop_back();
}
return;
}
public:
vector<vector<int>> combine(int n, int k) {
res.clear();
if(n<1 || k<1 ||k>n)
return res;
vector<int> p;
findCombination(n, k, 1, p);
return res;
}
};
-
(39组合总和) 给定一个无重复元素的数组
candidates
和一个目标数target
,找出candidates
中所有可以使数字和为target
的组合。candidates
中的数字可以无限制重复被选取。说明:
- 所有数字(包括
target
)都是正整数。 - 解集不能包含重复的组合。
示例:
输入:candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ]
/// Time Complexity: O(n^n) /// Space Complexity: O(target) class Solution { public: vector<vector<int>> combinationSum(vector<int> &candidates, int target) { vector<vector<int>> res; vector<int> cur_res; solve(candidates, 0, target, cur_res, res); return res; } private: void solve(const vector<int> &candidates, int index, int target, vector<int>& cur_res, vector<vector<int>>& res){ if(target == 0){ res.push_back(cur_res); return; } for(int i = index ; i < candidates.size() ; i ++) if(target >= candidates[i]){ cur_res.push_back(candidates[i]); solve(candidates, i, target - candidates[i], cur_res, res); cur_res.pop_back(); } return; } };
- 所有数字(包括
-
(40组合总和II) 给定一个数组 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] ]
class Solution { public: vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { sort(candidates.begin(), candidates.end()); vector<vector<int>> res; vector<int> cur_res; solve(candidates, 0, target, cur_res, res); return res; } private: void solve(const vector<int> &candidates, int index, int target, vector<int>& cur_res, vector<vector<int>>& res){ if(target == 0){ res.push_back(cur_res); return; } for(int i = index ; i < candidates.size() ; i ++){ if(i > index && candidates[i] == candidates[i-1]) continue; if(target >= candidates[i]){ cur_res.push_back(candidates[i]); solve(candidates, i + 1, target - candidates[i], cur_res, res); cur_res.pop_back(); } } return; } };
-
(216组合总和) 找出所有相加之和为 n 的 k* 个数的组合**。***组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
示例 1:
输入: k = 3, n = 7 输出: [[1,2,4]]
class Solution { public: vector<vector<int>> combinationSum3(int k, int n) { vector<vector<int>> res; vector<int> cur_res; solve(1, k, n, cur_res, res); return res; } private: void solve(int index, int k, int n, vector<int>& cur_res, vector<vector<int>>& res){ if(n == 0 && k == 0){ res.push_back(cur_res); return; } if(k == 0) return; for(int i = index ; i <= 9 ; i ++) if(n >= i){ cur_res.push_back(i); solve(i + 1, k - 1, n - i, cur_res, res); cur_res.pop_back(); } return; } };
-
(78子集) 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
示例:
输入: nums = [1,2,3] 输出: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
-
(90子集II) 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
示例:
输入: [1,2,2] 输出: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
-
(401二进制手表)二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。
每个 LED 代表一个 0 或 1,最低位在右侧。

示例:
输入: n = 1
返回: [“1:00”, “2:00”, “4:00”, “8:00”, “0:01”, “0:02”, “0:04”, “0:08”, “0:16”, “0:32”]
class Solution {
public:
vector<string> readBinaryWatch(int num) {
vector<string> res;
vector<bool> bits(10, false);
go(bits, 0, num, res);
return res;
}
private:
void go(vector<bool>& bits, int index, int num, vector<string>& res){
if(index == 10){
int h = 0;
for(int i = 0; i < 4; i ++) h = h * 2 + bits[i];
int m = 0;
for(int i = 4; i < 10; i ++) m = m * 2 + bits[i];
if(h < 12 && m < 60){
stringstream ss;
ss << h << ":" << setfill('0') << setw(2) << m;
res.push_back(ss.str());
}
return;
}
if(10 - index > num) go(bits, index + 1, num, res);
if(num){
bits[index] = true;
go(bits, index + 1, num - 1, res);
bits[index] = false;
}
return;
}
};
-
(79 单词搜索) 给定一个二维网格和一个单词,找出该单词是否存在于网格中。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
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 t[2][4] = { -1,0,1,0, 0,1,0,-1 }; vector<vector<bool>> used; // 在board[pos_i][pos_j]位置处,找到word[k] bool findPath(vector<vector<char>>& board, string& word, int pos_i, int pos_j, int k) { if (k == word.size()) return true; for (int i = 0; i < 4; i++) { int next_i = pos_i + t[0][i]; int next_j = pos_j + t[1][i]; if (next_i < 0 || next_i >= board.size() || next_j < 0 || next_j >= board[0].size()) continue; if (used[next_i][next_j]) continue; if (board[next_i][next_j] == word[k]) { used[next_i][next_j] = true; if (findPath(board, word, next_i, next_j, k + 1)) return true; used[next_i][next_j] = false; } } return false; } public: bool exist(vector<vector<char>>& board, string word) { if (board.size() == 0) return false; used = vector<vector<bool>>(board.size(), vector<bool>(board[0].size(), false)); bool ret = false; for (int i = 0; i < board.size(); i++) for (int j = 0; j < board[i].size(); j++) if (board[i][j] == word[0]) { used[i][j] = true; if (findPath(board, word, i, j, 1)) return true; used[i][j] = false; } return ret; } };
-
(200 岛屿数量) 给定一个由
'1'
(陆地)和'0'
(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。示例 :
输入: 11000 11000 00100 00011 输出: 3
class Solution { private: int m,n; int num; int d[4][2]={ { -1,0},{ 0,1},{ 1,0},{ 0,-1}}; vector<vector<bool> visited; bool inArea(int &x, int &y){ return (x>=0 && x < m && y>=0 && y<n); } // 以pos_i,pos_j为起点,将与其相连的陆地的visited置为true bool findIsland(vector<vector<char>>& grid, int &pos_i, int &pos_j){ if(grid[pos_i][pos_j]=='0') return false; if(vistited[pos_i][pos_j]) return false; visited[pos_i][pos_j]=true; for(int i=0;i<4;i++){ int next_i=pos_i+d[i][0]; int next_j=pos_j+d[i][1]; if(inArea(next_i, next_j) && !visited[next_i][next_j] && findIsland(grid, next_i, next_j) return true; } return false; } public: int numIslands(vector<vector<char>>& grid) { if(grid.size()==0) return 0; m=grid.size(); n=grid[0].size(); visited=vector<vector<bool>>(m, vector<bool>(n, false)); num=0; for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(findIsLand(grid, i, j)) num++; return num; } };
-
(130被围绕的区域) 给定一个二维的矩阵,包含
'X'
和'O'
(字母 O)。找到所有被
'X'
围绕的区域,并将这些区域里所有的'O'
用'X'
填充。示例:
X X X X X O O X X X O X X O X X
运行你的函数后,矩阵变为:
X X X X X X X X X X X X X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的
'O'
都不会被填充为'X'
。 任何不在边界上,或不与边界上的'O'
相连的'O'
最终都会被填充为'X'
。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。/// BFS /// Time Complexity: O(m*n) /// Space Complexity: O(m*n) class Solution { private: int m, n; int d[4][2] = { { 0,1}, { 1,0}, { 0,-1}, { -1,0}}; private: bool inArea(int x, int y){ return x >= 0 && y >= 0 && x < m && y < n; } bool bfs(const vector<vector<char>> &board, int x, int y, vector<vector<bool>>& visited, vector<pair<int,int>>& record){ queue<pair<int,int>> q; // return true if we can only get to 'X' during BFS, // otherwise, return false bool ret = true; visited[x][y] = true; q.push(pair<int,int>(x, y)); while( !q.empty()){ pair<int, int> cur = q.front(); q.pop(); record.push_back(pair<int, int>(cur.first, cur.second)); for(int i = 0 ; i < 4 ;i ++){ int newX = cur.first + d[i][0]; int newY = cur.second + d[i][1]; if(!inArea(newX, newY)) // If newX, newY is not in the area, // it means we get out of the board in this BFS, // we need to return false in this case ret = false; else if(board[newX][newY] == 'O' && !visited[newX][newY]){ visited[newX][newY] = true; q.push(pair<int, int>(newX, newY)); } } } return ret; } public: void solve(vector<vector<char>>& board) { m = board.size(); if(m == 0) return; n = board[0].size(); if(n == 0) return; vector<vector<bool>> visited(m, vector<bool>(n, false)); vector<pair<int,int>> record; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (board[i][j] == 'O' && !visited[i][j]){ // clear record before each time we run BFS record.clear(); if(bfs(board, i, j, visited, record)) // If BFS return true, // means from this position, // we will not get out of the board. // As a result, we can make every position we visited in this BFS from 'O' to 'X' for(int k = 0 ; k < record.size() ; k ++) board[record[k].first][record[k].second] = 'X'; } return; } };
-
(417太平洋大西洋水流问题) 给定一个
m x n
的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示:
- 输出坐标的顺序不重要
- m 和 n 都小于150
示例:
给定下面的 5x5 矩阵: 太平洋 ~ ~ ~ ~ ~ ~ 1 2 2 3 (5) * ~ 3 2 3 (4) (4) * ~ 2 4 (5) 3 1 * ~ (6) (7) 1 4 5 * ~ (5) 1 1 2 4 * * * * * * 大西洋 返回: [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).
/// Floodfill /// Time Complexity: O(m*n) /// Space Complexity: O(m*n) class Solution { private int n, m; private boolean[][] pacific, atlantic; private int[][] d = { { 0, 1}, { 0, -1}, { 1, 0}, { -1, 0}}; public List<int[]> pacificAtlantic(int[][] matrix) { ArrayList<int[]> res = new ArrayList<>(); n = matrix.length; if(n == 0) return res; m = matrix[0].length; pacific = new boolean[n][m]; atlantic = new boolean[n][m]; for(int i = 0 ; i < n ; i ++){ dfs(matrix, pacific, i, 0); dfs(matrix, atlantic, i, m - 1); } for(int j = 0 ; j < m ; j ++){ dfs(matrix, pacific, 0, j); dfs(matrix, atlantic, n - 1, j); } for(int i = 0 ; i < n ; i ++) for(int j = 0 ; j < m ; j ++) if(pacific[i][j] && atlantic[i][j]) res.add(new int[]{ i, j}); return res; } private void dfs(int[][] matrix, boolean[][] visited, int x, int y){ visited[x][y] = true; for(int i = 0 ; i < 4 ; i ++){ int newX = x + d[i][0]; int newY = y + d[i][1]; if(inArea(newX, newY) && !visited[newX][newY] && matrix[newX][newY] >= matrix[x][y]) dfs(matrix, visited, newX, newY); } } private boolean inArea(int x, int y){ return x >= 0 && x < n && y >= 0 && y < m; } public static void printList(List<int[]> list){ for(int[] e: list) System.out.print("[ " + e[0] + " , " + e[1] + " ] "); System.out.println(); }
-
(51 N皇后) n皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q'
和 '.'
分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
class Solution {
private:
vector<vector<string>> res;
vector<string> one_res;
vector<bool> row;
vector<bool> col;
vector<bool> dia1;
vector<bool> dia2;
// 对于第index个皇后,尝试在第index行的c列摆放
void findSolution(int n, int index, int c) {
if (index >= n) {
res.push_back(one_res);
return;
}
if (row[index] || col[c] || dia1[index + c] || dia2[index - c + n - 1])
return;
row[index] = true;
col[c] = true;
dia1[index + c] = true;
dia2[index - c + n - 1] = true;
one_res[index][c] = 'Q';
for (int i = 0; i < n; i++) {
findSolution(n, index + 1, i);
if (index + 1 >= n)
break;
}
row[index] = false;
col[c] = false;
dia1[index + c] = false;
dia2[index - c + n - 1] = false;
one_res[index][c] = '.';
return;
}
public:
vector<vector<string>> solveNQueens(int n) {
if (n == 0)
return res;
row = vector<bool>(n, false);
col = vector<bool>(n, false);
dia1 = vector<bool>(2 * n - 1, false);
dia2 = vector<bool>(2 * n - 1, false);
one_res = vector<string>(n, string(n, '.'));
for (int i = 0; i < n; i++)
findSolution(n, 0, i);
return res;
}
};
- (37解数独) 编写一个程序,通过填充空格来解决数独问题。
/// Backtracking
/// Time Complexity: O(n^{need to fill})
/// Space Complexity: O(9*9)
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
vector<vector<bool>> row(9, vector<bool>(10, false));
vector<vector<bool>> col(9, vector<bool>(10, false));
vector<vector<bool>> block(9, vector<bool>(10, false));
for(int i = 0; i < 9; i ++)
for(int j = 0; j < 9; j ++)
if(board[i][j] != '.'){
row[i][board[i][j] - '0'] = true;
col[j][board[i][j] - '0'] = true;
block[i / 3 * 3 + j / 3][board[i][j] - '0'] = true;
}
for(int i = 0; i < 81; i ++)
if(board[i / 9][i % 9] == '.'){
assert(dfs(board, i, row, col, block));
return;
}
}
private:
bool dfs(vector<vector<char>>& board, int pos,
vector<vector<bool>>& row, vector<vector<bool>>& col,
vector<vector<bool>>& block){
if(pos == 81)
return true;
int next = pos + 1;
for(; next < 81; next ++)
if(board[next / 9][next % 9] == '.')
break;
int x = pos / 9, y = pos % 9;
for(int i = 1; i <= 9; i ++)
if(!row[x][i] && !col[y][i] && !block[x / 3 * 3 + y / 3][i]){
row[x][i] = true;
col[y][i] = true;
block[x / 3 * 3 + y / 3][i] = true;
board[x][y] = '0' + i;
if(dfs(board, next, row, col, block))
return true;
row[x][i] = false;
col[y][i] = false;
block[x / 3 * 3 + y / 3][i] = false;
board[x][y] = '.';
}
return false;
}
};