leetcode–DFS、BFS

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 });
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柴寺仓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值