当前位置:   article > 正文

LeetCode刷题 -- DFS_leetcode dfs

leetcode dfs

深度优先搜索算法,depth-first-search DFS,是一种用于遍历或者搜索树、图的算法,这个算法会尽可能深的去搜索树的分支。

深度优先搜索是图论中的经典算法,DFS基于递归思想,实质是一种借助递归实现的枚举。

基本代码结构

  1. void dfs(int step) {
  2. // 判断边界;
  3. // 尝试每一种可能;
  4. int len = getXxxLen();//define your own length
  5. for (int i = 1; i <= len; ++i) {
  6. //继续下一步
  7. dfs(step + 1);
  8. }
  9. // 返回;
  10. }

例题

113. 路径总和 II

题目

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

分析:

这题的思路就是深度遍历,利用递归的方式,从根节点一直遍历到叶子节点,然后记录所有满足要求的路径。

问题点:

1、那种路径是满足要求的?

        ---> 只要从根节点一直加到叶子节点,和刚好等于目标值就是满足要求

2、满足要求的路径,怎么存储?

        ---> 定义一个LinkedList,用于存储遍历路径上的所有节点的值

                遍历到某个节点时,就把这个节点的值添加进去

                如果某个节点不符合要求,要跳出这个节点,遍历其他节点,就把这个不符合要求的节点的值,从当前LinkedList中删除,也就是删除最后一次插入的那个值。

        

代码

  1. // 定义全局变量,用于方法返回值
  2. List<List<Integer>> result = new ArrayList<>();
  3. // 定义一个LinkedList,用于存储单个遍历路径上的数值
  4. LinkedList<Integer> list = new LinkedList<>();
  5. public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
  6. // 定义路径上所有的和
  7. int sum = 0;
  8. dfs(root, targetSum, sum);
  9. return result;
  10. }
  11. // 定义dfs方法
  12. void dfs(TreeNode root, int targetSum, int sum) {
  13. if (root == null) {
  14. return;
  15. }
  16. // 将当前节点的value值,存到链表中
  17. list.add(root.val);
  18. // 路径和加上当前节点的值
  19. sum += root.val;
  20. // 如果当前节点为叶子节点,并且此时路径和刚好等于目标值,那么就将数据list添加到result中
  21. if (root.left == null && root.right == null && sum == targetSum) {
  22. // 注意这个地方,添加的时候,要new一个list,不能把当前list传进去,
  23. // 否则dfs跳出的时候,list里面的值也没了
  24. result.add(new ArrayList<>(list));
  25. }
  26. // 递归调用dfs方法
  27. dfs(root.left, targetSum, sum);
  28. dfs(root.right, targetSum, sum);
  29. // 关键这一步,如果跳出了当前的dfs方法,那么要把当前节点的值,从list中移除。
  30. list.removeLast();
  31. }
  1. class Solution:
  2. def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
  3. res = []
  4. cur_list = []
  5. def dfs(node, sum_value, target):
  6. if not node:
  7. return
  8. cur_list.append(node.val)
  9. sum_value += node.val
  10. if not node.left and not node.right and sum_value == target:
  11. res.append(list(cur_list))
  12. dfs(node.left, sum_value, target)
  13. dfs(node.right, sum_value, target)
  14. cur_list.pop()
  15. dfs(root, 0, targetSum)
  16. return res

 124. 二叉树中的最大路径和

题目

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点

分析:

 一个二叉树,a为当前递归调用中的传入的根节点(左右节点分别是已经计算好的最大子路径),注意题目,同一个节点在一条路径中最多出现一次,因此,最大路径可能情况是

  1. a节点不连接父节点
    1. a
    2. a+left
    3. a+right
    4. a + left + right 
  2.   a节点连接父节点,为了保证路径上节点最多出现一次,那么左右节点就只能选择一个,
    1. parent + a + right  -- right大则选择right
    2. parent + a + left   -- left大则选择left

此外,因为节点有负值的情况,因此,如果节点为负的情况下,要想办法舍弃负值

代码

  1. public class Test124 {
  2. // 定义一个最大值,因为节点的值可能为负
  3. // 因此初始化值,设置为Integer.MIN_VALUE
  4. int maxValue = Integer.MIN_VALUE;
  5. public int maxPathSum(TreeNode root) {
  6. getMaxPath(root);
  7. return maxValue;
  8. }
  9. // dfs方法,寻找最大的子节点路径path
  10. private int getMaxPath(TreeNode root) {
  11. // 当前节点为null,对路径和没有贡献,因此返回值0;
  12. if (null == root) {
  13. return 0;
  14. }
  15. // 递归调用左右子节点
  16. // 如果子节点求出来的路径和最大值为负数,对路径和没有贡献
  17. // 因此,取0 和 返回值 较大的一个值
  18. int leftMaxPath = Math.max(0, getMaxPath(root.left));
  19. int rightMaxPath = Math.max(0, getMaxPath(root.right));
  20. // 更新最大路径和,当前要比较的对象是本节点值,加上左右节点最大贡献值
  21. maxValue = Math.max(maxValue, root.val + leftMaxPath + rightMaxPath);
  22. // 返回值,注意此处,因为同一个节点在一条路径只能出现一次
  23. // 因此,返回值要设置为,当前节点的值 加上 左右 节点 比较大的贡献哪个路径。
  24. return root.val + Math.max(leftMaxPath, rightMaxPath);
  25. }
  26. }
  1. class Solution:
  2. def __init__(self):
  3. self.max_value = None
  4. def maxPathSum(self, root: Optional[TreeNode]) -> int:
  5. self.max_value = -(sys.maxsize - 1)
  6. def dfs(node):
  7. if not node:
  8. return 0
  9. left_max = max(0, dfs(node.left))
  10. right_max = max(0, dfs(node.right))
  11. self.max_value = max(self.max_value, node.val + left_max + right_max)
  12. return node.val + max(left_max, right_max)
  13. dfs(root)
  14. return self.max_value

130. 被围绕的区域

题目:

给你一个 m x n 的矩阵 board ,由若干字符 'X' 和 'O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

分析:

这到提要理解清楚,什么是被X围绕的O,弄清题意之后可知:对于所有边界上的O以及和边界上的O直接相连的O,都不属于被X围绕,而剩下的O,就是被X围绕了。

根据这个思路,可以进行如下解:

首先遍历边界上的值,将所有的O,并且与这个O直接相连的O,全部找出来(可以用到深DFS方式)并标记为A

此时,当前数组上所有的O就是被X包围的,可以直接改成X,然后在吧标记为A的,在改回O

注意:O和0很像,键盘也离得近,注意注意在注意o_O;

代码:

  1. public class Test130 {
  2. public void solve(char[][] board) {
  3. if (board == null) {
  4. return;
  5. }
  6. int m = board.length;
  7. int n = board[0].length;
  8. // 上下两行进行遍历
  9. for (int i = 0; i < board[0].length; i++) {
  10. edgeO(board, 0, i);
  11. edgeO(board, m - 1, i);
  12. }
  13. // 左右两列进行遍历
  14. for (int i = 1; i < m - 1; i++) {
  15. edgeO(board, i, 0);
  16. edgeO(board, i, n - 1);
  17. }
  18. // 最后遍历整个数组,将之前没有标记为A的,改成X
  19. // 将之前标记为A的,改回为O
  20. for (int i = 0; i < board.length; i++) {
  21. for (int j = 0; j < board[i].length; j++) {
  22. if (board[i][j] == 'O') {
  23. board[i][j] = 'X';
  24. }
  25. if (board[i][j] == 'A') {
  26. board[i][j] = 'O';
  27. }
  28. }
  29. }
  30. }
  31. public void edgeO(char[][] board, int x, int y) {
  32. int m = board.length;
  33. int n = board[0].length;
  34. // 数组不越界,并且值为O的时候,将值先标记为A
  35. if (x < m && x >= 0 && y < n && y >= 0 && board[x][y] == 'O') {
  36. board[x][y] = 'A';
  37. edgeO(board, x - 1, y);
  38. edgeO(board, x + 1, y);
  39. edgeO(board, x, y - 1);
  40. edgeO(board, x, y + 1);
  41. }
  42. }
  43. }
  1. class Solution:
  2. def solve(self, board: List[List[str]]) -> None:
  3. m, n = len(board), len(board[0])
  4. def dfs(i, j):
  5. if i < 0 or j < 0 or i >= m or j >= n or board[i][j] != "O":
  6. return
  7. board[i][j] = "A"
  8. dfs(i - 1, j)
  9. dfs(i + 1, j)
  10. dfs(i, j - 1)
  11. dfs(i, j + 1)
  12. for i in range(n):
  13. if board[0][i] == "O":
  14. dfs(0, i)
  15. if board[m - 1][i] == "O":
  16. dfs(m - 1, i)
  17. for i in range(m):
  18. if board[i][0] == "O":
  19. dfs(i, 0)
  20. if board[i][n - 1] == "O":
  21. dfs(i, n - 1)
  22. for i in range(m):
  23. for j in range(n):
  24. # 注意这个改变的顺序,如果先从A改成O,那么下面又会从O改成X,就出问题了
  25. if board[i][j] == "O":
  26. board[i][j] = "X"
  27. if board[i][j] == "A":
  28. board[i][j] = "O"

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/117818
推荐阅读
相关标签
  

闽ICP备14008679号