标签: 深度优先搜索

LeetCode刷题【851】喧闹和富有

有一组 n 个人作为实验对象,从 0n - 1 编号,其中每个人都有不同数目的钱,以及不同程度的安静值(quietness)。为了方便起见,我们将编号为 x 的人简称为 “person x “。

给你一个数组 richer ,其中 richer[i] = [ai, bi] 表示 person ai 比 person bi 更有钱。另给你一个整数数组 quiet ,其中 quiet[i] 是 person i 的安静值。richer 中所给出的数据 逻辑自洽(也就是说,在 person x 比 person y 更有钱的同时,不会出现 person y 比 person x 更有钱的情况 )。

现在,返回一个整数数组 answer 作为答案,其中 answer[x] = y 的前提是,在所有拥有的钱肯定不少于 person x 的人中,person y 是最安静的人(也就是安静值 quiet[y] 最小的人)。

 

示例 1:

输入:richer = [[1,0],[2,1],[3,1],[3,7],[4,3],[5,3],[6,3]], quiet = [3,2,5,4,6,1,7,0]
输出:[5,5,2,5,4,5,6,7]
解释: 
answer[0] = 5,
person 5 比 person 3 有更多的钱,person 3 比 person 1 有更多的钱,person 1 比 person 0 有更多的钱。
唯一较为安静(有较低的安静值 quiet[x])的人是 person 7,
但是目前还不清楚他是否比 person 0 更有钱。
answer[7] = 7,
在所有拥有的钱肯定不少于 person 7 的人中(这可能包括 person 3,4,5,6 以及 7),
最安静(有较低安静值 quiet[x])的人是 person 7。
其他的答案也可以用类似的推理来解释。

示例 2:

输入:richer = [], quiet = [0]
输出:[0]
 

提示:

  • n == quiet.length
  • 1 <= n <= 500
  • 0 <= quiet[i] < n
  • quiet 的所有值 互不相同
  • 0 <= richer.length <= n * (n - 1) / 2
  • 0 <= ai, bi < n
  • ai != bi
  • richer 中的所有数对 互不相同
  • richer 的观察在逻辑上是一致的
Related Topics
  • 深度优先搜索
  • 拓扑排序
  • 数组

  • 👍 204
  • 👎 0
  • DFS,还可以再优化下

    1. 遍历int[][] richer数组,生成一个map,构建当前节点和比他小的person节点的关联关系
    2. 在遍历的过程中,同时知道了哪些节点没有比他大的节点,存放于HashSet<Integer> starter
    3. starter遍历逐个进行DFS,利用int[] quiet数组中对应的喧嚣值往下深搜的时候代入更新到结果int[] ans数组中
    4. 由于在初始化的时候赋值了Arrays.fill(ans,501)每个值为501,所以如果当前喧嚣值比当前的ans[i]大或者等于的话就不用继续往下更新了
    5. 最终int[] ans数组中存的是当前对应的quiet值,又因为quiet 的所有值 互不相同所以根据反向映射关系重新赋值更新为对应的person
    6. 其实int[] ans中也可以一开始就存对应的person,不用最终再转换一遍,但是一开始用quiet来比较运算比较直观点,所以就先这么写了
    7. 最终结果返映射的时候,如果当前ans[i]依然等于501,说明这个点是独立的,不和其他点有相关联,那么对应依旧为quiet[i]
    8. int[] ans数组也可以一开始就等于int[] quiet数组,但是这样的话再dfs过程中判断大小的时候需要再借助其他手段判断是否需要再往下层更新

    代码

    class Solution {
    
    //     richer = [[1,0],[2,1],[3,1],[3,7],[4,3],[5,3],[6,3]],
    //     quiet = [3,2,5,4,6,1,7,0]
    //        6    5
    //        ↓  ↙
    //    2   3  ←  4
    //    ↓ ↙   ↘
    //    1       7
    //    ↓
    //    0
    
        HashMap<Integer, HashSet<Integer>> map = new HashMap<>();
        int[] ans;
        int[] quiet;
        int[] quietToPerson;
    
        public int[] loudAndRich(int[][] richer, int[] quiet) {
            this.quiet = quiet;
            ans = new int[quiet.length];
            Arrays.fill(ans,501);
            quietToPerson = new int[quiet.length];
            for (int i = 0; i < quiet.length; i++) {
                quietToPerson[quiet[i]] = i;
            }
    
            HashSet<Integer> starter = new HashSet<>();
            for (int[] ints : richer) {
                if (!map.containsKey(ints[0])){
                    map.put(ints[0],new HashSet<>());
                }
                map.get(ints[0]).add(ints[1]);
                starter.remove(ints[1]);
                starter.add(ints[0]);
            }
            starter.forEach(i -> {
                dfs(i,quiet[i]);
            });
    
            for (int i = 0; i < ans.length; i++) {
                ans[i]= quietToPerson[ans[i]>500?quiet[i]:ans[i]];
            }
            return ans;
        }
    
        public void dfs(int num, int min){
            if (min > quiet[num]){
                min = quiet[num];
            }
            if (ans[num] > min){
                ans[num] = min;
            }else{
                return;
            }
            if (map.containsKey(num)){
                int finalMin = min;
                map.get(num).forEach(integer -> {
                    dfs(integer, finalMin);
                });
            }
        }
    }

    LeetCode刷题【114】二叉树展开为链表

    给你二叉树的根结点 root ,请你将它展开为一个单链表:

    • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
    • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

     

    示例 1:

    输入:root = [1,2,5,3,4,null,6]
    输出:[1,null,2,null,3,null,4,null,5,null,6]
    

    示例 2:

    输入:root = []
    输出:[]
    

    示例 3:

    输入:root = [0]
    输出:[0]
    

     

    提示:

    • 树中结点数在范围 [0, 2000]
    • -100 <= Node.val <= 100

     

    进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

    Related Topics
    • 深度优先搜索
    • 链表
    • 二叉树

  • 👍 1219
  • 👎 0
  • 前序遍历,原地递归修改
    按照题意为前序遍历的结果,声明一个TreeNode pre记录前一个访问的节点

    这样直接进行前序遍历,把当前节点挂载到pre节点的right上,记得要清除left节点

    遍历当前节点的时候leftright节点的值记得先存下来,会在递归的时候被修改掉

    代码

    class Solution {
        /*
            1
        2       5
      3   4   n   6
    
            1
          n   2
            n   3
              n   4
                n   5
                  n   6
    
         */
        TreeNode pre;
        public void flatten(TreeNode root) {
            dfs(root);
        }
    
    
        public void dfs(TreeNode node){
            if (null == node){
                return;
            }
            if (pre!=null){
                pre.right = node;
            }
            pre = node;
            TreeNode left = node.left;
            TreeNode right = node.right;
            node.left = null;
            dfs(left);
            dfs(right);
        }
    }

    LeetCode刷题【637】二叉树的层平均值

    给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。

     

    示例 1:

    输入:root = [3,9,20,null,null,15,7]
    输出:[3.00000,14.50000,11.00000]
    解释:第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
    因此返回 [3, 14.5, 11] 。
    

    示例 2:

    输入:root = [3,9,20,15,7]
    输出:[3.00000,14.50000,11.00000]
    

     

    提示:

    • 树中节点数量在 [1, 104] 范围内
    • -231 <= Node.val <= 231 - 1
    Related Topics
    • 深度优先搜索
    • 广度优先搜索
    • 二叉树

  • 👍 354
  • 👎 0
  • bfs

    class Solution {
    
        public List<Double> averageOfLevels(TreeNode root) {
            List<Double> res = new ArrayList<>();
            if (null == root){
                return res;
            }
            Queue<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()){
                int size = queue.size();
                double sum = 0;
                int i=-1;
                while (++i < size){
                    TreeNode node = queue.poll();
                    sum += (double) node.val;
                    if (node.left!=null){
                        queue.offer(node.left);
                    }
                    if (node.right!=null){
                        queue.offer(node.right);
                    }
                }
                res.add(sum/size);
            }
            return res;
        }
    }

    LeetCode刷题【1034】边界着色

    给你一个大小为 m x n 的整数矩阵 grid ,表示一个网格。另给你三个整数 rowcolcolor 。网格中的每个值表示该位置处的网格块的颜色。

    两个网格块属于同一 连通分量 需满足下述全部条件:

    • 两个网格块颜色相同
    • 在上、下、左、右任意一个方向上相邻

    连通分量的边界 是指连通分量中满足下述条件之一的所有网格块:

    • 在上、下、左、右任意一个方向上与不属于同一连通分量的网格块相邻
    • 在网格的边界上(第一行/列或最后一行/列)

    请你使用指定颜色 color 为所有包含网格块 grid[row][col]连通分量的边界 进行着色,并返回最终的网格 grid

     

    示例 1:

    输入:grid = [[1,1],[1,2]], row = 0, col = 0, color = 3
    输出:[[3,3],[3,2]]

    示例 2:

    输入:grid = [[1,2,2],[2,3,2]], row = 0, col = 1, color = 3
    输出:[[1,3,3],[2,3,3]]

    示例 3:

    输入:grid = [[1,1,1],[1,1,1],[1,1,1]], row = 1, col = 1, color = 2
    输出:[[2,2,2],[2,1,2],[2,2,2]]

     

    提示:

    • m == grid.length
    • n == grid[i].length
    • 1 <= m, n <= 50
    • 1 <= grid[i][j], color <= 1000
    • 0 <= row < m
    • 0 <= col < n

     

    Related Topics
    • 深度优先搜索
    • 广度优先搜索
    • 数组
    • 矩阵

  • 👍 147
  • 👎 0
  • 海星,理解了题意的话就比较简单了(补充更新)
    给个图吧,题目写得太拗口了

    给出如图的矩阵grid[][],给出了对应坐标row = 3col = 4,和一个color随便是什么,并不重要

    要求把row, col位置连通分量的边界的值修改为color

    题目中并给出了连通分量的定义,即四个方向中任意一个方向上相邻,且值相等的区块,那么自然的边界的定义我们就能理解出来,如果上下左右4个方向上有任意一个和连通分量的值不同的话,那么就可以说明这个格子是边框,且如果这个连通分量格子本身是矩阵的边界的话,那么他也是边框

    那么按照题意,这个图上的应该要修改的位置就是如下

    理解了这层的话就好办了,直接上DFS

    代码

    class Solution {
    
        int[][] grid;
        int m;
        int n;
        int connectedComponentValue;
        int borderColor;
        boolean[][] visited;
        int[][] dir = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
    
        public int[][] colorBorder(int[][] grid, int row, int col, int color) {
            this.grid = grid;
            m = grid.length;
            n = grid[0].length;
            visited = new boolean[m][n];
            connectedComponentValue = grid[row][col];
            borderColor = color;
    
            dfs(row,col);
    
            return this.grid;
        }
    
        public void dfs(int row, int col){
            boolean borderFlag = false;
            visited[row][col] = true;
            for (int[] ints : dir) {
                int x = row + ints[0];
                int y = col + ints[1];
    
                if (isOutOfBoundary(x,y)){
                    borderFlag = true;
                    continue;
                }
                if (visited[x][y]){
                    continue;
                }
                if (grid[x][y] != connectedComponentValue){
                    borderFlag = true;
                    continue;
                }
                dfs(x,y);
            }
            if (borderFlag){
                grid[row][col] = borderColor;
            }
        }
    
    //    boolean isEdge(int row, int col){
    //        return row == 0 || col == 0 || row == m-1 || col==n-1;
    //    }
    
        boolean isOutOfBoundary(int row, int col){
            return row < 0 || col < 0 || row >= m || col >= n;
        }
    }

    补充更新个小细节

    1. isOutOfBoundary判断需要在visited[x][y]之前,为了防止发生越界错误
    2. grid[x][y] != connectedComponentValue判断需要在visited[x][y]之后,深搜会先改变染色掉之前访问到的格子,如果不先判断visited[x][y]的话会导致类似缩圈的效果,把整个连通区域全都染色

    LeetCode刷题【剑指 Offer 68 – I】二叉搜索树的最近公共祖先

    给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

    百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

    例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

     

    示例 1:

    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
    输出: 6 
    解释: 节点 2 和节点 8 的最近公共祖先是 6。
    

    示例 2:

    输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
    输出: 2
    解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

     

    说明:

    • 所有节点的值都是唯一的。
    • p、q 为不同节点且均存在于给定的二叉搜索树中。

    注意:本题与主站 235 题相同:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/

    Related Topics
    • 深度优先搜索
    • 二叉搜索树
    • 二叉树

  • 👍 239
  • 👎 0
  • 二叉搜索树特性

    1. 递归

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (p.val > q.val){
                return lowestCommonAncestor(root,q,p);
            }
            if (root.val == p.val || root.val == q.val){
                return root;
            }
            if (root.val > p.val && root.val > q.val){
                return lowestCommonAncestor(root.left,p,q);
            }
            if (root.val < p.val && root.val < q.val){
                return lowestCommonAncestor(root.right,p,q);
            }
            return root;
        }
    }

    2. 指针

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (p.val > q.val){
                return lowestCommonAncestor(root,q,p);
            }
            TreeNode cur = root;
            while ((cur.val > p.val && cur.val >q.val) || (cur.val < p.val && cur.val <q.val)){
                if (cur.val > p.val && cur.val >q.val){
                    cur = cur.left;
                }
                if (cur.val < p.val && cur.val <q.val){
                    cur = cur.right;
                }
            }
            return cur;
        }
    }

    比较简单,不做过多分析了

    LeetCode刷题【剑指 Offer 55 – II】平衡二叉树

    输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

     

    示例 1:

    给定二叉树 [3,9,20,null,null,15,7]

        3
       / \
      9  20
        /  \
       15   7

    返回 true

    示例 2:

    给定二叉树 [1,2,2,3,3,null,null,4,4]

           1
          / \
         2   2
        / \
       3   3
      / \
     4   4
    

    返回 false

     

    限制:

    • 0 <= 树的结点个数 <= 10000

    注意:本题与主站 110 题相同:https://leetcode-cn.com/problems/balanced-binary-tree/

     

    Related Topics
    • 深度优先搜索
    • 二叉树

  • 👍 288
  • 👎 0
  • DFS深搜模板套用

    解题思路

    1. 借助深搜模板,计算每层对应高度
    2. 判断每个节点的左右子节点高度相差是否小于2
    3. 如果不小于2则不是平衡二叉树

    代码

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
    
        boolean isBalanced = true;
        public boolean isBalanced(TreeNode root) {
            dfs(root,0);
            return isBalanced;
        }
    
        public int dfs(TreeNode node, int dep){
            if (!isBalanced || null == node){
                return dep;
            }
            dep++;
            int leftDep = dfs(node.left,dep);
            int rightDep = dfs(node.right,dep);
            if (Math.abs(leftDep-rightDep )< 2){
                return Math.max(leftDep,rightDep);
            }
            isBalanced = false;
            return Math.max(leftDep,rightDep);
        }
    }

    LeetCode刷题【559】N 叉树的最大深度

    给定一个 N 叉树,找到其最大深度。

    最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

    N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。

     

    示例 1:

    输入:root = [1,null,3,2,4,null,5,6]
    输出:3
    

    示例 2:

    输入:root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
    输出:5
    

     

    提示:

    • 树的深度不会超过 1000
    • 树的节点数目位于 [0, 104] 之间。
    Related Topics
  • 深度优先搜索
  • 广度优先搜索

  • 👍 288
  • 👎 0
  • 深搜

    遍历树并记录更新最大深度

    class Solution {
        int deep = 0;
        public int maxDepth(Node root) {
            dfs(root,0);
    
            return deep;
        }
    
        public void dfs(Node node,int current){
            if (null == node){
                return ;
            }
            current++;
            deep = Math.max(deep,current);
            for (Node child : node.children){
                dfs(child,current);
            }
        }
    }
    

    广搜也可以,按层遍历记录最终的层数,代码比较简单不做赘述