leetcode–DFS、BFS
22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
输入:n = 3
输出:[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”]
思路:回溯法,长度满足2n返回
Python
def generateParenthesis(n: int):
res = []
def dfs(cur, l, r):
if len(cur) == 2 * n: # 长度满足返回
print(cur)
res.append(''.join(cur))
return
if l < n:
cur.append('(')
dfs(cur, l + 1, r)
cur.pop()
if r < l:
cur.append(')')
dfs(cur, l, r + 1)
cur.pop()
dfs([], 0, 0)
return res
C++
void dfs(vector<string>& res, string& cur, int n, int l, int r)
{
if (cur.size() == 2 * n) {
res.push_back(cur);
return;
}
if (l < n) {
cur += "(";
dfs(res, cur, n, l + 1, r);
cur.pop_back();
}
if (r < l) {
cur += ")";
dfs(res, cur, n, l, r + 1);
cur.pop_back();
}
}
vector<string> generateParenthesis(int n) {
vector<string> res;
string cur;
dfs(res, cur, n, 0, 0);
return res;
}
37. 解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
思路:回溯法,找到行、列、块的交集,进行回溯
def solveSudoku(board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
row = [set(range(1, 10)) for _ in range(9)] # 行
col = [set(range(1, 10)) for _ in range(9)] # 列
block = [set(range(1, 10)) for _ in range(9)] # 块
empty = []
for i in range(9):
for j in range(9):
if board[i][j] == '.':
empty.append((i, j))
else:
val = int(board[i][j])
row[i].remove(val)
col[j].remove(val)
block[(i // 3) * 3 + j // 3].remove(val)
def dfs(idx):
if idx == len(empty):
return True
i, j = empty[idx]
v = (i // 3) * 3 + j // 3
for value in row[i] & col[j] & block[v]:
row[i].remove(value)
col[j].remove(value)
block[v].remove(value)
board[i][j] = str(value)
if dfs(idx + 1):
return True
row[i].add(value)
col[j].add(value)
block[v].add(value)
return False
dfs(0)
40. 组合总和 II
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
思路:先排序,回溯索引需要指向下一个,防止重复需要剪枝
Python
def combinationSum2(candidates: List[int], target: int) -> List[List[int]]:
candidates.sort()
res = []
def dfs(cur, begin, val):
if val == target:
res.append(cur[:])
return
for k in range(begin, len(candidates)):
if val + candidates[k] > target: # 大于直接break
break
if k > begin and candidates[k] == candidates[k - 1]: # 去重剪枝
continue
cur.append(candidates[k])
dfs(cur, k + 1, val + candidates[k])
cur.pop()
dfs([], 0, 0)
return res
C++
void dfs(vector<vector<int>>& res, vector<int>& cur, int target, vector<int>& candidates, int begin)
{
if (accumulate(cur.begin(), cur.end(), 0) == target)
{
res.push_back(cur);
return;
}
if (accumulate(cur.begin(), cur.end(), 0) < target)
{
for (int i = begin; i < candidates.size(); i++)
{
if (i > begin && candidates[i] == candidates[i - 1]) {
continue;
}
cur.push_back(candidates[i]);
dfs(res, cur, target, candidates, i + 1);
cur.pop_back();
}
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int>> res;
vector<int> cur;
dfs(res, cur, target, candidates, 0);
return res;
}
47. 全排列 II
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
输入:nums = [1,1,2]
输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
思路:先排序,增加列表表示当前位置是否被用过,防止重复需要剪枝
Python
def permuteUnique(nums: List[int]) -> List[List[int]]:
nums.sort()
used = [False for _ in range(len(nums))] # 记录是否用过
res = []
def dfs(cur, used):
if len(cur) == len(nums):
res.append(cur[:])
return
for i in range(len(nums)):
if not used[i]:
if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]: # 防止重复
continue
cur.append(nums[i])
used[i] = True
dfs(cur, used)
cur.pop()
used[i] = False
dfs([], used)
return res
C++
void dfs(vector<vector<int>>& res, vector<int>& cur, vector<int>& path, vector<int>& nums)
{
if (cur.size() == nums.size()) {
res.push_back(cur);
return;
}
for (int i = 0; i < nums.size(); ++i) {
if (!path[i]) continue;
if (i > 0 && nums[i] == nums[i - 1] && path[i - 1]) continue;
cur.push_back(nums[i]);
path[i] = 0;
dfs(res, cur, path, nums);
cur.pop_back();
path[i] = 1;
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
vector<int> cur;
vector<int> path(nums.size(), 1);
dfs(res, cur, path, nums);
return res;
}
79. 单词搜索
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
思路:设置四个方向,增加列表表示当前位置是否被用过,从每个起始位置开始回溯
def exist(board: List[List[str]], word: str) -> bool:
dir = [(1, 0), (-1, 0), (0, 1), (0, -1)] # 记录方向
begin = []
row = len(board)
col = len(board[0])
used = [[False] * col for _ in range(row)] # 记录位置是否使用过
for r in range(row):
for c in range(col):
if board[r][c] == word[0]:
begin.append((r, c))
def dfs(index, i, j, used):
if index == len(word):
return True
for d in dir:
ci = i + d[0]
cj = j + d[1]
if 0 <= ci < row and 0 <= cj < col and board[ci][cj] == word[index]:
if used[ci][cj]:
continue
used[ci][cj] = True
if dfs(index + 1, ci, cj, used):
return True
else:
used[ci][cj] = False
for i, j in begin: # 每个起始位置开始回溯
used[i][j] = True
if dfs(1, i, j, used):
return True
else:
used[i][j] = False
return False
286. 墙与门
你被给定一个 m × n 的二维网格 rooms ,网格中有以下三种可能的初始化值:
-1 表示墙或是障碍物
0 表示一扇门
INF 无限表示一个空的房间。然后,我们用 231 - 1 = 2147483647 代表 INF。你可以认为通往门的距离总是小于 2147483647 的。
你要给每个空房间位上填上该房间到 最近门的距离 ,如果无法到达门,则填 INF 即可。
输入:rooms = [[2147483647,-1,0,2147483647],[2147483647,2147483647,2147483647,-1],[2147483647,-1,2147483647,-1],[0,-1,2147483647,2147483647]]
输出:[[3,-1,0,1],[2,2,1,-1],[1,-1,2,-1],[0,-1,3,4]]
思路:使用广度优先搜索,从门的位置开始BFS,直到没有空的房间
Python
def wallsAndGates(rooms: List[List[int]]) -> None:
"""
Do not return anything, modify rooms in-place instead.
"""
row = len(rooms)
col = len(rooms[0])
INF = 2147483647
if row == 0:
return
queue = []
for r in range(row):
for c in range(col):
if rooms[r][c] == 0:
queue.append((r, c, 0))
while queue:
i, j, step = queue.pop(0)
for di, dj in [(-1, 0), (1, 0), (0, 1), (0, -1)]:
ci = di + i
cj = dj + j
if 0 <= ci < row and 0 <= cj < col and rooms[ci][cj] == INF:
rooms[ci][cj] = step + 1
queue.append((ci, cj, step + 1))
C++
const int INF = 2147483647;
void wallsAndGates(vector<vector<int>>& rooms) {
deque<vector<int>> dq;
int row = rooms.size();
int col = rooms[0].size();
for (int r = 0; r < row; ++r) {
for (int c = 0; c < col; ++c) {
if (rooms[r][c] == 0) {
dq.push_back({ r, c, 0 });
}
}
}
while (!dq.empty()) {
int r = dq[0][0];
int c = dq[0][1];
int distance = dq[0][2];
dq.pop_front();
for (auto x : vector<pair<int, int>>{ {-1,0}, {1,0}, {0,-1}, {0,1} }) {
int cr = r + x.first;
int cc = c + x.second;
if (0 <= cr && cr < row && 0 <= cc && cc < col && rooms[cr][cc] == INF) {
rooms[cr][cc] = distance + 1;
dq.push_back({ cr, cc, distance + 1 });
}
}
}
}