日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法 - DFS/BFS

發布時間:2023/12/4 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法 - DFS/BFS 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

DFS函數大概率會傳遞“位置信息”,根據位置信息獲取下一步的選擇,(大部分是在循環中)選擇、執行、回退
例如N皇后的 棋盤位置(x, y),組合問題的 idx

DFS函數的目的是,確定“當前位置”的選擇,然后將問題拋給下一個遞歸過程

在哪做選擇,就在哪退出選擇,參考題9

def DFS():# 出口if 滿足出口條件:將滿足條件的路徑加入結果方法返回for 選擇 in 選擇列表:# 做選擇將該選擇從選擇列表移除路徑.add(選擇)DFS(路徑, 選擇列表)# 撤銷選擇路徑.remove(選擇)將該選擇再加入選擇列表

DFS和BFS本質上是決策樹的遍歷
動態規劃要求重疊子問題的條件,而DFS/BFS則是沒有任何條件的純暴力搜索。而且,BFS找到的路徑一定是最短的,但代價通常比DFS要大得多。

DFS通常的問題形式是,找各種意義的路徑:棋盤擺放、集合劃分等等。
BFS通常的問題形式是,尋找(決策樹上的)最短路徑。

畫出遞歸樹,想想每個節點該怎么做

文章目錄

  • 1.DFS - N皇后問題
  • 2.DFS - 子集(冪集)
  • 3.DFS - 組合
  • 4.DFS - 括號生成
  • 5.BFS - 二叉樹的最小深度
  • 6.BFS - 轉盤鎖
  • 7.DFS - 組合總數
  • 8.字符串的全排列
  • 9.是否存在word路徑

1.DFS - N皇后問題

  • 每個格子都面臨選擇:放或者不放皇后
  • 注意一個優化點:如果某行放了皇后,則下次遞歸直接跳到下行
class Solution(object):res = []def solveNQueens(self, n):""":type n: int:rtype: List[List[str]]"""self.res = []path = [["." for _ in range(n)] for _ in range(n)]self.dfs(path, 0, 0, n)return self.resdef dfs(self, path, x, y, queens_left):n = len(path)# 出口if queens_left == 0:path_strs = []for i in range(n):path_strs.append("".join(path[i]))self.res.append(path_strs)returnelif x > n - 1 or y > n - 1:return# 一般情況# 選擇1:放皇后is_queen_available = Truefor k in range(n): # 檢查行和列is_queen_available = False if path[x][k] == "Q" else is_queen_availableis_queen_available = False if path[k][y] == "Q" else is_queen_availabletemp_x, temp_y = x - 1, y - 1 # 檢查左上方和右上方while (temp_x >= 0 and temp_y >= 0):if path[temp_x][temp_y] == "Q":is_queen_available = Falsetemp_x -= 1temp_y -= 1temp_x, temp_y = x - 1, y + 1while (temp_x >= 0 and temp_y <= n - 1):if path[temp_x][temp_y] == "Q":is_queen_available = Falsetemp_x -= 1temp_y += 1if is_queen_available:path[x][y] = "Q" # 做選擇queens_left -= 1self.dfs(path, x + 1, 0, queens_left)path[x][y] = "." # 撤銷選擇queens_left += 1# 選擇2:不放皇后if y == n - 1:x_new = x + 1y_new = 0else:x_new = xy_new = y + 1self.dfs(path, x_new, y_new, queens_left)

2.DFS - 子集(冪集)

  • 每次遞歸都面臨問題:是否將下標 idx 的數字加入結果集
  • 撤銷選擇使用 path.pop() 而不能使用 path = path[: -1]
class Solution(object):res = []def subsets(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""self.res = [[]]def dfs(path, nums, idx):# 出口if idx > len(nums) - 1:return# 做選擇:idx放入結果path.append(nums[idx])self.res.append(path[:])dfs(path, nums, idx + 1)path.pop() # 撤銷選擇,不能使用 path = path[: -1]# 做選擇:idx不放入結果dfs(path, nums, idx + 1)dfs([], nums, 0)return self.res

3.DFS - 組合

  • 給定兩個整數 n 和 k,返回范圍 [1, n] 中所有可能的 k 個數的組合
  • 沒有思路時畫出樹結構幫助分析
class Solution(object):res = []path = []def combine(self, n, k):""":type n: int:type k: int:rtype: List[List[int]]"""self.res = []self.path = []def dfs(n, k, idx):if len(self.path) == k:self.res.append(self.path[:])return# 站在當前的位置:path已有一些值,則要遍歷idx及之后的所有選項for i in range(idx, n + 1):self.path.append(i)dfs(n, k, i + 1)self.path.pop()dfs(n, k, 1)return self.res

4.DFS - 括號生成

  • 數字 n 代表生成括號的對數,請你設計一個函數,用于能夠生成所有可能的并且 有效的 括號組合。
  • 有效括號組合需滿足:左括號必須以正確的順序閉合。
class Solution(object):res = []path = []def generateParenthesis(self, n):""":type n: int:rtype: List[str]"""self.res = []self.path = []def dfs(n, l, r):# 出口if r == n:self.res.append("".join(self.path))return# 做選擇# 1.左右括號相等,只能添加左括號if l == r:self.path.append("(")dfs(n, l + 1, r)self.path.pop()# 2.左括號大于右括號,且l<n,能添加左也能添加右else:if l < n: # 可以加左括號self.path.append("(")dfs(n, l + 1, r)self.path.pop()self.path.append(")")dfs(n, l, r + 1)self.path.pop()dfs(n, 0, 0)return self.res########################################################################################### """用字符串記錄path,沒有回溯""" class Solution(object):res = []def generateParenthesis(self, n):""":type n: int:rtype: List[str]"""self.res = []self.find(n, "", 0, 0)return self.resdef find(self, n, s, left, right):# 出口if left == n and right == n:self.res.append(s)# 做出所有的選擇# 如果左括號不大于右括號,只能添加左括號elif left <= right:self.find(n, s + "(", left + 1, right)# 可以添加右括號,也能添加左括號(如果還能添加)else:if left != n:self.find(n, s + "(", left + 1, right)self.find(n, s + ")", left, right + 1)

5.BFS - 二叉樹的最小深度

找好搜索的結束條件,當一個節點沒有左右子節點時,到達葉節點。

# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def minDepth(self, root):""":type root: TreeNode:rtype: int"""if root is None:return 0queue = [root]depth = 1while (len(queue) > 0):length = len(queue)for i in range(length):temp_node = queue[i]# 結束條件if temp_node.left is None and temp_node.right is None:return depthif temp_node.left is not None:queue.append(temp_node.left)if temp_node.right is not None:queue.append(temp_node.right)queue = queue[length:]depth += 1

6.BFS - 轉盤鎖

class Solution(object):def openLock(self, deadends, target):""":type deadends: List[str]:type target: str:rtype: int"""# 工具方法def plus(num, bit):origin = int(num[bit])if origin < 9:origin += 1else:origin = 0if bit == 0:return str(origin) + num[1: ]elif bit == 3:return num[0: 3] + str(origin)else:return num[0: bit] + str(origin) + num[bit + 1: ]def minus(num, bit):origin = int(num[bit])if origin > 0:origin -= 1else:origin = 9if bit == 0:return str(origin) + num[1: ]elif bit == 3:return num[0: 3] + str(origin)else:return num[0: bit] + str(origin) + num[bit + 1: ]# 特判if "0000" in deadends:return -1# BFSadded = ["0000"] # 不走回頭路,重要!queue = ["0000"]times = 0while (len(queue) > 0):length = len(queue)for i in range(length):code = queue[i]# 出口if code == target:return times# 處理每一位for j in range(4):temp_code = plus(code, j) # +1if temp_code not in deadends and temp_code not in added:queue.append(temp_code)added.append(temp_code)temp_code = minus(code, j) # -1if temp_code not in deadends and temp_code not in added:queue.append(temp_code)added.append(temp_code)times += 1queue = queue[length:]return -1

以上為經典的BFS解法。對于已知終點的BFS問題,可以采用雙向BFS加速運行,從起點和終點向中間擴展,直到出現交集。

int openLock(String[] deadends, String target) {Set<String> deads = new HashSet<>();for (String s : deadends) deads.add(s);// 用集合不用隊列,可以快速判斷元素是否存在Set<String> q1 = new HashSet<>();Set<String> q2 = new HashSet<>();Set<String> visited = new HashSet<>();int step = 0;q1.add("0000");q2.add(target);while (!q1.isEmpty() && !q2.isEmpty()) {// 哈希集合在遍歷的過程中不能修改,用 temp 存儲擴散結果Set<String> temp = new HashSet<>();/* 將 q1 中的所有節點向周圍擴散 */for (String cur : q1) {/* 判斷是否到達終點 */if (deads.contains(cur))continue;if (q2.contains(cur))return step;visited.add(cur);/* 將一個節點的未遍歷相鄰節點加入集合 */for (int j = 0; j < 4; j++) {String up = plusOne(cur, j);if (!visited.contains(up))temp.add(up);String down = minusOne(cur, j);if (!visited.contains(down))temp.add(down);}}/* 在這里增加步數 */step++;// temp 相當于 q1// 這里交換 q1 q2,下一輪 while 就是擴散 q2q1 = q2;q2 = temp;}return -1; }

7.DFS - 組合總數

給你一個 無重復元素 的整數數組 candidates 和一個目標整數 target ,找出 candidates 中可以使數字和為目標數 target 的 所有 不同組合 ,并以列表形式返回。你可以按 任意順序 返回這些組合。candidates 中的 同一個 數字可以 無限制重復被選取 。如果至少一個數字的被選數量不同,則兩種組合是不同的。

  • 如何保證同一元素可被無限選取?
class Solution(object):res = []path = []def combinationSum(self, candidates, target):""":type candidates: List[int]:type target: int:rtype: List[List[int]]"""self.res = []self.path = []def dfs(candidates, target, now_sum, idx):# 出口if now_sum == target and self.path not in self.res:self.res.append(self.path[:])returnelif now_sum > target:return# 做選擇for i in range(idx, len(candidates)):self.path.append(candidates[i])now_sum += candidates[i]dfs(candidates, target, now_sum, i) # 此步是保證同一數字無限選擇的關鍵,《i從idx開始》now_sum -= candidates[i]self.path.pop()dfs(candidates, target, 0, 0)return self.res

8.字符串的全排列

  • 標準的模板,參考文章開頭
class Solution(object):def permutation(self, s):""":type s: str:rtype: List[str]"""# 一個全排列問題# 用DFS"""在DFS做選擇/撤銷時,加入path!!!!!!!!!!!!!!!!!!!!!!!!"""length = len(s)path = []visited = [0 for _ in range(length)]res = []def dfs(s, length):# 遞歸出口if sum(visited) == length:resstr = "".join(path)if resstr not in res:res.append(resstr)return # 做選擇+撤銷選擇for i in range(length):if visited[i] == 0:visited[i] = 1path.append(s[i])dfs(s, length)path.pop()visited[i] = 0dfs(s, length)return res

9.是否存在word路徑

  • 不能在注釋處“撤銷選擇”,因為“做選擇”是在dfs開始是進行的,不能從子選項中回退
class Solution:def hasPath(self , matrix , word ):def dfs(x, y, m, n, pos):visited[x][y] = True # 在這個層面上做的選擇,不能從子選項中回退path.append(matrix[x][y])if pos == len(word) - 1:return True# 做選擇+撤銷選擇res = Falselx, ly = x, y - 1if ly >= 0 and not visited[lx][ly] and matrix[lx][ly] == word[pos + 1]:res = res or dfs(lx, ly, m, n, pos + 1) # visited[lx][ly] = False # path.pop()rx, ry = x, y + 1if ry < n and not visited[rx][ry] and matrix[rx][ry] == word[pos + 1]:res = res or dfs(rx, ry, m, n, pos + 1) # visited[rx][ry] = False # path.pop()ux, uy = x - 1, yif ux >= 0 and not visited[ux][uy] and matrix[ux][uy] == word[pos + 1]:res = res or dfs(ux, uy, m, n, pos + 1) # visited[ux][uy] = False # path.pop()dx, dy = x + 1, yif dx < m and not visited[dx][dy] and matrix[dx][dy] == word[pos + 1]:res = res or dfs(dx, dy, m, n, pos + 1) # visited[dx][dy] = False # path.pop()visited[x][y] = False # 應該在這里撤銷選擇path.pop()return resm = len(matrix)if m == 0:return Falsen = len(matrix[0])if n == 0:return Falsevisited = [[False for _ in range(n)] for _ in range(m)]path = []for i in range(m):for j in range(n):if matrix[i][j] == word[0]:res = dfs(i, j, m, n, 0)if res:return Truereturn False
  • 如果想在各個選項中“選擇”并“撤銷”,可以采用下面的寫法,但初始條件要修改
class Solution:def hasPath(self , matrix , word ):def dfs(x, y, m, n, pos):if pos == len(word) - 1:return True # 做選擇+撤銷選擇res = False lx, ly = x, y - 1if ly >= 0 and not visited[lx][ly] and matrix[lx][ly] == word[pos + 1]:visited[lx][ly] = True path.append(word[pos + 1])res = res or dfs(lx, ly, m, n, pos + 1)visited[lx][ly] = False path.pop()rx, ry = x, y + 1if ry < n and not visited[rx][ry] and matrix[rx][ry] == word[pos + 1]:visited[rx][ry] = True path.append(word[pos + 1])res = res or dfs(rx, ry, m, n, pos + 1)visited[rx][ry] = False path.pop()ux, uy = x - 1, y if ux >= 0 and not visited[ux][uy] and matrix[ux][uy] == word[pos + 1]:visited[ux][uy] = True path.append(word[pos + 1])res = res or dfs(ux, uy, m, n, pos + 1)visited[ux][uy] = False path.pop()dx, dy = x + 1, y if dx < m and not visited[dx][dy] and matrix[dx][dy] == word[pos + 1]:visited[dx][dy] = True path.append(word[pos + 1])res = res or dfs(dx, dy, m, n, pos + 1)visited[dx][dy] = False path.pop() return res m = len(matrix)if m == 0:return False n = len(matrix[0])if n == 0:return False visited = [[False for _ in range(n)] for _ in range(m)]for i in range(m):for j in range(n):if matrix[i][j] == word[0]:path = [word[0]]visited[i][j] = Trueres = dfs(i, j, m, n, 0) if res:return True visited[i][j] = False return False

總結

以上是生活随笔為你收集整理的算法 - DFS/BFS的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。