1 介绍
本博客用来记录代码随想录leetcode200题之回溯算法相关题目。
2 训练
题目1:77. 组合
C++代码如下,
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
if (cur.size() == k) {
res.emplace_back(cur);
return;
}
for (int j = i; j <= n; ++j) {
cur.emplace_back(j);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(1);
return res;
}
};
python3代码如下,
调用库函数写法,
import itertools
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
numbers = [i for i in range(1,n+1)]
res = itertools.combinations(numbers, k)
res = [list(combination) for combination in res]
return res
回溯写法,
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
cur = []
def dfs(i: int) -> None:
nonlocal res, cur
if len(cur) == k:
res.append(copy.deepcopy(cur))
return
for j in range(i,n+1):
cur.append(j)
dfs(j+1)
cur = cur[0:-1]
return
dfs(1)
return res
题目2:77. 组合
带剪枝写法!
C++代码如下,
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
if (cur.size() == k) {
res.emplace_back(cur);
return;
}
for (int j = i; j + k - cur.size() - 1 <= n; ++j) {
cur.emplace_back(j);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(1);
return res;
}
};
python3代码如下,
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
res = []
cur = []
def dfs(i: int):
nonlocal n, k, res, cur
if len(cur) == k:
res.append(copy.deepcopy(cur))
return
for j in range(i,n+1):
if j + k - len(cur) - 1 > n: #剪枝
break
cur.append(j)
dfs(j+1)
del cur[-1]
return
dfs(1)
return res
题目3:216. 组合总和 III
C++代码如下,
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
int s = accumulate(cur.begin(), cur.end(), 0);
if (s > n) return;
else if (s == n && cur.size() == k) res.emplace_back(cur);
for (int j = i; j + k - cur.size() - 1 <= 9; ++j) {
cur.emplace_back(j);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(1);
return res;
}
};
python3代码如下,
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
res = []
cur = []
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
s = nums
for i in range(8,-1,-1):
s[i] += s[i+1]
#print(f"s={s}")
def dfs(i: int) -> None:
nonlocal res, cur, n, k
if sum(cur) == n and len(cur) == k:
res.append(copy.deepcopy(cur))
return
for j in range(i,10):
if i + k - len(cur) - 1 > 9:
break
if sum(cur) + sum(s[i:]) < n:
break
cur.append(j)
dfs(j+1)
del cur[-1]
return
dfs(1)
return res
题目4:17. 电话号码的字母组合
C++代码如下,
class Solution {
public:
vector<string> letterCombinations(string digits) {
if (digits == "") return {}; //特判
vector<string> res;
string cur = "";
map<char,string> map_digit_str = {
{'2',"abc"},
{'3',"def"},
{'4',"ghi"},
{'5',"jkl"},
{'6',"mno"},
{'7',"pqrs"},
{'8',"tuv"},
{'9',"wxyz"}
};
function<void(int)> dfs =[&] (int i) -> void {
if (cur.size() == digits.size()) {
res.emplace_back(cur);
return;
}
for (char c : map_digit_str[digits[i]]) {
cur += c;
dfs(i+1);
cur.pop_back();
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if digits == "": #特判
return []
map_digit_str = {
'2':'abc',
'3':'def',
'4':'ghi',
'5':'jkl',
'6':'mno',
'7':'pqrs',
'8':'tuv',
'9':'wxyz'
}
res = []
cur = ""
def dfs(i: int) -> None:
nonlocal res,cur,map_digit_str,digits
if i == len(digits):
res.append(cur)
return
c = digits[i]
s = map_digit_str[c]
for t in s:
cur += t
dfs(i+1)
cur = cur[:-1]
return
dfs(0)
return res
题目5:39. 组合总和
C++代码如下,
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
int s = accumulate(cur.begin(), cur.end(), 0);
if (s > target) return;
else if (s == target) res.emplace_back(cur);
for (int j = i; j < candidates.size() && s + candidates[j] <= target; ++j) {
cur.emplace_back(candidates[j]);
dfs(j);
cur.pop_back();
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
cur = []
candidates.sort()
def dfs(i: int) -> None:
nonlocal candidates, target, res, cur
s = sum(cur)
if s > target:
return
elif s == target:
res.append(copy.deepcopy(cur))
for j in range(i,len(candidates)):
if s + candidates[j] > target:
break
cur.append(candidates[j])
dfs(j)
del cur[-1]
return
dfs(0)
return res
题目6:40. 组合总和 II
C++代码如下,
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> cur;
sort(candidates.begin(), candidates.end());
function<void(int)> dfs =[&] (int i) -> void {
int s = accumulate(cur.begin(), cur.end(), 0);
if (s > target) return;
else if (s == target) res.emplace_back(cur);
for (int j = i; j < candidates.size() && s + candidates[j] <= target; ++j) {
if (j != i && candidates[j] == candidates[j-1]) {//同层级去重
continue;
}
cur.emplace_back(candidates[j]);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
cur = []
candidates.sort()
def dfs(i: int) -> None:
s = sum(cur)
if s > target:
return
elif s == target:
res.append(copy.deepcopy(cur))
for j in range(i,len(candidates)):
if s + candidates[j] > target:
break
if j != i and candidates[j] == candidates[j-1]: #同一树层去除重复
continue
cur.append(candidates[j])
dfs(j+1)
del cur[-1]
return
dfs(0)
return res
题目7:131. 分割回文串
C++代码如下,
class Solution {
public:
bool check(string &t) {
int n = t.size();
for (int i = 0; i < n / 2; ++i) {
if (t[i] != t[n-1-i]) return false;
}
return true;
}
vector<vector<string>> partition(string s) {
vector<vector<string>> res;
vector<string> cur;
function<void(int)> dfs =[&] (int i) -> void {
if (i == s.size()) {
res.emplace_back(cur);
return;
}
for (int j = i+1; j <= s.size(); ++j) {
int length = j - i;
string t = s.substr(i, length);
if (check(t)) {
cur.emplace_back(t);
dfs(j);
cur.pop_back();
}
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def partition(self, s: str) -> List[List[str]]:
res = []
cur = []
def dfs(i: int) -> None:
nonlocal s, res, cur
if i == len(s):
res.append(copy.deepcopy(cur))
for j in range(i+1,len(s)+1):
t = s[i:j]
if t == t[::-1]:
cur.append(t)
dfs(j)
del cur[-1]
return
dfs(0)
return res
题目8:93. 复原 IP 地址
C++代码如下,
class Solution {
public:
bool check(string &s) {
if (s.size() > 3) return false;
int num = stoi(s);
if (num < 0 || num > 255) return false;
if (s[0] == '0' && s.size() > 1) return false;
return true;
}
vector<string> restoreIpAddresses(string s) {
vector<string> res;
vector<string> cur;
function<void(int)> dfs =[&](int i) -> void {
if (cur.size() > 4) return;
if (cur.size() == 4 && i == s.size()) {
string ss = cur[0];
for (int i = 1; i < 4; ++i) ss += "." + cur[i];
res.emplace_back(ss);
return;
}
for (int j = i + 1; j <= s.size(); ++j) {
int length = j - i;
string t = s.substr(i, length);
if (check(t)) {
cur.emplace_back(t);
dfs(j);
cur.pop_back();
}
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
res = []
cur = []
def check(t: str) -> bool:
num = int(t)
if num < 0 or num > 255:
return False
if t[0] == '0' and len(t) > 1:
return False
return True
def dfs(i: int) -> None:
nonlocal s, res, cur
if len(cur) > 4: #剪枝
return
if i == len(s) and len(cur) == 4:
ss = ".".join(cur)
res.append(ss)
return
for j in range(i+1,len(s)+1):
t = s[i:j]
if check(t):
cur.append(t)
dfs(j)
del cur[-1]
return
dfs(0)
return res
题目9:78. 子集
C++代码如下,
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
res.emplace_back(cur);
if (i >= nums.size()) return;
for (int j = i; j < nums.size(); ++j) {
cur.emplace_back(nums[j]);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
递归写法,
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
cur = []
def dfs(i: int) -> None:
nonlocal nums, res, cur
res.append(copy.deepcopy(cur))
if i >= len(nums):
return
for j in range(i,len(nums)):
cur.append(nums[j])
dfs(j+1)
del cur[-1]
return
dfs(0)
return res
非递归写法,
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
i = 0
res = []
while i < (1<<n):
t = i
cur = []
for j in range(n):
if (i >> j) & 1:
cur.append(nums[j])
res.append(copy.deepcopy(cur))
i += 1
return res
题目10:90. 子集 II
C++代码如下,
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> res;
vector<int> cur;
sort(nums.begin(), nums.end());
function<void(int)> dfs =[&] (int i) -> void {
res.emplace_back(cur);
if (i >= nums.size()) return;
for (int j = i; j < nums.size(); ++j) {
if ((j != i) && (nums[j] == nums[j-1])) continue;
cur.emplace_back(nums[j]);
dfs(j+1);
cur.pop_back();
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
cur = []
def dfs(i: int) -> None:
res.append(copy.deepcopy(cur))
if i >= len(nums):
return
for j in range(i,len(nums)):
if (j != i) and nums[j] == nums[j-1]:
continue
cur.append(nums[j])
dfs(j+1)
del cur[-1]
return
dfs(0)
return res
题目11:491. 非递减子序列
C++代码如下,
class Solution {
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
vector<vector<int>> res;
vector<int> cur;
function<void(int)> dfs =[&] (int i) -> void {
if (cur.size() >= 2) res.emplace_back(cur);
if (cur.size() >= nums.size()) return;
unordered_set<int> visited;
for (int j = i; j < nums.size(); ++j) {
if (cur.empty() || cur.back() <= nums[j]) {
if (visited.count(nums[j]) != 0) continue; //同层级结点去除重复
visited.insert(nums[j]);
cur.emplace_back(nums[j]);
dfs(j+1);
cur.pop_back();
}
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
res = []
cur = []
def dfs(i: int) -> None:
nonlocal nums, res, cur
if len(cur) >= 2:
res.append(copy.deepcopy(cur))
if len(cur) >= len(nums):
return
visited = set()
for j in range(i,len(nums)):
if len(cur) == 0 or cur[-1] <= nums[j]:
if nums[j] in visited: #同层级结点去除重复
continue
visited.add(nums[j])
cur.append(nums[j])
dfs(j+1)
del cur[-1]
return
dfs(0)
return res
题目12:46. 全排列
C++代码如下,
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
vector<int> cur;
int n = nums.size();
vector<bool> visited(n, false);
function<void()> dfs =[&]() -> void {
if (cur.size() == n) {
res.emplace_back(cur);
return;
}
for (int i = 0; i < n; ++i) {
if (!visited[i]) {
cur.emplace_back(nums[i]);
visited[i] = true;
dfs();
cur.pop_back();
visited[i] = false;
}
}
return;
};
dfs();
return res;
}
};
python3代码如下,
手写递归版本,
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []
cur = []
visited = [False] * n
def dfs() -> None: #递归的参数是visited
nonlocal n, nums, res, cur, visited
if len(cur) == n:
res.append(copy.deepcopy(cur))
return
for j in range(0,n):
if visited[j] == False:
visited[j] = True
cur.append(nums[j])
dfs()
del cur[-1]
visited[j] = False
return
dfs()
return res
调用库函数版本,
import itertools
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
return list(itertools.permutations(nums))
题目13:47. 全排列 II
C++代码如下,
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> res;
vector<int> cur;
vector<bool> visited(n, false);
function<void()> dfs =[&] () -> void { //递归的是visited
if (cur.size() == n) {
res.emplace_back(cur);
return;
}
unordered_set<int> level;
for (int i = 0; i < n; ++i) {
if (visited[i] == false && level.count(nums[i]) == 0) {
level.insert(nums[i]);
cur.emplace_back(nums[i]);
visited[i] = true;
dfs();
visited[i] = false;
cur.pop_back();
}
}
return;
};
dfs();
return res;
}
};
python3代码如下,
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []
cur = []
visited = [False] * n
def dfs() -> None:
nonlocal nums, n, res, cur, visited
if len(cur) == n:
res.append(copy.deepcopy(cur))
return
level = set()
for i in range(0, n):
if visited[i] == False and nums[i] not in level:
level.add(nums[i])
visited[i] = True
cur.append(nums[i])
dfs()
visited[i] = False
del cur[-1]
return
dfs()
return res
题目14:332. 重新安排行程
C++代码如下,
class Solution {
public:
vector<string> findItinerary(vector<vector<string>>& tickets) {
sort(tickets.begin(), tickets.end());
unordered_map<string, vector<string>> map_s_es;
for (auto ticket : tickets) {
string s = ticket[0];
string e = ticket[1];
map_s_es[s].emplace_back(e);
}
vector<string> res;
function<void(string s)> dfs =[&] (string s) -> void {
while (map_s_es[s].size() > 0) {
string e = map_s_es[s][0];
map_s_es[s].erase(map_s_es[s].begin());
dfs(e);
}
res.insert(res.begin(), s);
};
dfs("JFK");
return res;
}
};
python3代码如下,
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
tickets.sort()
map_s_es = collections.defaultdict(list)
for s,e in tickets:
map_s_es[s].append(e)
res = []
def dfs(s: str) -> None:
while map_s_es[s]:
dfs(map_s_es[s].pop(0))
res.insert(0, s)
dfs("JFK")
return res
题目15:51. N 皇后
C++代码如下,
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<string> cur(n, string(n, '.'));
vector<bool> rows(n, false);
vector<bool> cols(n, false);
vector<bool> angle(2 * n, false);
vector<bool> unangle(2 * n, false);
function<void(int)> dfs =[&] (int i) -> void {
//第i行摆放皇后
if (i == n) {
res.emplace_back(cur);
return;
}
for (int j = 0; j < n; ++j) {
if (cols[j] == false && angle[i+j] == false && unangle[i-j+n] == false) {
rows[i] = true;
cols[j] = angle[i+j] = unangle[i-j+n] = true;
cur[i][j] = 'Q';
dfs(i+1);
rows[i] = false;
cols[j] = angle[i+j] = unangle[i-j+n] = false;
cur[i][j] = '.';
}
}
return;
};
dfs(0);
return res;
}
};
python3代码如下,
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
res = []
cur = [['.'] * n for _ in range(n)]
cols = [False] * n
rows = [False] * n
angle = [False] * (2 * n)
unangle = [False] * (2 * n)
def dfs(i: int) -> None:
#从第i行开始摆放
if i == n:
t = []
for row in cur:
t.append("".join(row))
res.append(t)
for j in range(n):
if cols[j] == False and angle[i+j] == False and unangle[i-j+n] == False:
rows[i] = True
cols[j] = angle[i+j] = unangle[i-j+n] = True
cur[i][j] = 'Q'
dfs(i+1)
rows[i] = False
cols[j] = angle[i+j] = unangle[i-j+n] = False
cur[i][j] = '.'
return
dfs(0)
return res
题目16:37. 解数独
C++代码如下,
class Solution {
public:
void solveSudoku(vector<vector<char>>& board) {
int v = (1 << 9) - 1;
vector<int> rows(9, v);
vector<int> cols(9, v);
vector<vector<int>> boxes(3, vector<int>(3, v));
unordered_map<int, int> map_val_ones;
for (int val = 0; val < (1 << 9); ++val) {
for (int i = 0; i < 9; ++i) {
map_val_ones[val] += val >> i & 1;
}
}
unordered_map<int, int> map_val_idx;
for (int i = 0; i < 9; ++i) {
map_val_idx[1<<i] = i;
}
function<void(int,int,int)> changest =[&] (int i, int j, int x) -> void {
board[i][j] = '0' + x;
x -= 1;
v = 1 << x;
rows[i] -= v;
cols[j] -= v;
boxes[i/3][j/3] -= v;
return;
};
function<void(int,int)> unchangest =[&] (int i, int j) -> void {
int x = board[i][j] - '0';
board[i][j] = '.';
x -= 1;
v = 1 << x;
rows[i] += v;
cols[j] += v;
boxes[i/3][j/3] += v;
return;
};
function<int(int,int)> get_x =[&] (int i, int j) {
return rows[i] & cols[j] & boxes[i/3][j/3];
};
function<int(int)> low_bit =[&] (int x) -> int {
return x & -x;
};
function<bool(int)> dfs =[&] (int cnt) -> bool {
if (cnt == 0) return true;
int ii = -1;
int jj = -1;
int v = 9;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') {
int x = get_x(i, j);
if (map_val_ones[x] < v) {
ii = i;
jj = j;
v = map_val_ones[x];
}
}
}
}
//枚举(ii,jj)处填入何值
int val = get_x(ii, jj);
while (val > 0) {
int t = low_bit(val);
int idx = map_val_idx[t];
changest(ii, jj, idx + 1);
if (dfs(cnt-1)) return true;
unchangest(ii, jj);
val -= t;
}
return false;
};
int cnt = 0;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') cnt += 1;
else {
int x = board[i][j] - '0';
changest(i, j, x);
}
}
}
dfs(cnt);
return;
}
};
python3代码如下,
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
#v的二进制表示中第i为1表示该位置处可以填i+1
v = (1 << 9) - 1
rows = [v] * 9
cols = [v] * 9
boxes = [[v] * 3 for _ in range(3)]
map_x_ones = collections.defaultdict(int) #x的二进制表示中有多少个1
x = 0
while x < (1 << 9):
#求x中有多少个1
for i in range(9):
map_x_ones[x] += x >> i & 1
x += 1
map_val_idx = collections.defaultdict(int) #val表示2的几次方
for i in range(9):
map_val_idx[1 << i] = i
def low_bit(x: int) -> int:
return x & -x
def get(i: int, j: int) -> int:
x = rows[i] & cols[j] & boxes[i//3][j//3]
return x
def do(i: int, j: int, x: int) -> None: #在(i,j)处由.改为x
board[i][j] = str(x)
x -= 1
v = 1 << x
rows[i] -= v
cols[j] -= v
boxes[i//3][j//3] -= v
return
def undo(i: int, j: int) -> None: #在(i,j)处由board[i][j]改为.
x = board[i][j]
board[i][j] = '.'
x = int(x)
x -= 1
v = 1 << x
rows[i] += v
cols[j] += v
boxes[i//3][j//3] += v
return
def dfs(k: int) -> bool: #正在填第k个空格
if k == 0:
return True
ii = -1
jj = -1
v = 9
for i in range(9):
for j in range(9):
if board[i][j] == '.':
x = get(i, j)
if map_x_ones[x] < v:
ii, jj = i, j
v = map_x_ones[x]
#枚举(ii,jj)处填入什么
x = get(ii, jj)
while x > 0:
t = low_bit(x)
idx = map_val_idx[t]
do(ii, jj, idx + 1)
if dfs(k-1):
return True
undo(ii, jj)
x -= t
return False
cnt = 0
for i in range(9):
for j in range(9):
if board[i][j] == '.':
cnt += 1
else:
x = int(board[i][j])
do(i, j, x)
dfs(cnt)
return board