hot100-二叉树

news2025/3/31 8:36:20

二叉树

二叉树递归

相当于这个的顺序来回调换

class Solution {
    private List<Integer> res = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root == null)return res;
        inorderTraversal(root.left);
        res.add(root.val);
        inorderTraversal(root.right);
        return res;
    }
}

二叉树迭代

前序遍历

迭代法
public List<Integer> preOrderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<Integer>();
    if (root == null) {
        return res;
    }
    
    Deque<TreeNode> stack = new LinkedList<TreeNode>();
    TreeNode node = root;
    while (!stack.isEmpty() || node != null) {
        while (node != null) {
            res.add(node.val);
            stack.push(node);
            node = node.left;
        }
        node = stack.pop();
        node = node.right;
    }
    return res;
}

中序遍历

迭代法
public List<Integer> preOrderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<Integer>();
    if (root == null) {
        return res;
    }
    
    Deque<TreeNode> stack = new LinkedList<TreeNode>();
    TreeNode node = root;
    while (!stack.isEmpty() || node != null) {
        while (node != null) {
            stack.push(node);
            node = node.left;
        }
        node = stack.pop();
        res.add(node.val);
        node = node.right;
    }
    return res;
}

染色法

缺点是要写一个pair的类,优点是只需要更改顺序就可以使三个顺序都能写

class Pair<K, V> {
    private K key;
    private V value;

    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        Deque<Pair<Integer, TreeNode>> stack = new ArrayDeque<>();
        stack.push(new Pair<>(0,root));
        while(!stack.isEmpty()){
            Pair<Integer,TreeNode> newPair = stack.pop();
            int color = newPair.getKey();
            TreeNode node = newPair.getValue();
            if(node == null)continue;
            if(color == 0){
                stack.push(new Pair<>(0,node.right));
                stack.push(new Pair<>(1,node));
                stack.push(new Pair<>(0,node.left));
            }else{
                res.add(node.val);
            }
        }
        return res;
    }
}
Morris法

①第一个循环:是否为空

②判断左子树是否为空,是则记录+进入右子树,不是则进入左子树

③如果最右的最右为空,则链接,进入左子树。如果最右的最右为root,则断联,记录,进入右子树。

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        while(root !=null){
            if(root.left == null){
                res.add(root.val);
                root = root.right;
            }else{
                //有左子树的情况
                TreeNode pre = root.left;
                while(pre.right != null && pre.right != root){
                    pre = pre.right;
                }
                if(pre.right == null){
                    pre.right = root;
                    root = root.left;
                }else{
                    pre.right = null;//断开
                    res.add(root.val);
                    root = root.right;
                }
            }
        }
        return res;
    }
}

后序遍历

反转法

其实就是将递归暗处的栈变成明面

public class PostorderTraversal {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;

        Stack<TreeNode> stack = new Stack<>();
        Stack<Integer> output = new Stack<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            output.push(node.val);

            if (node.left != null) stack.push(node.left);
            if (node.right != null) stack.push(node.right);
        }

        while (!output.isEmpty()) {
            result.add(output.pop());
        }

        return result;
    }
访问标记法(染色法)

(使用额外的标记来指示节点是否已经访问)

public class PostorderTraversal {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;

        Stack<TreeNode> stack = new Stack<>();
        TreeNode prev = null;

        while (!stack.isEmpty() || root != null) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }

            root = stack.peek();
            if (root.right == null || root.right == prev) {
                result.add(root.val);
                stack.pop();
                prev = root;
                root = null; // We have finished this node
            } else {
                root = root.right; // Move to the right child
            }
        }

        return result;
    }
Morris法(线性时间,常数空间)

Morris 遍历法通过在遍历过程中使用指针而避免了使用栈或递归,从而节省空间。

public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        if (root == null) return result;

        TreeNode dummy = new TreeNode(0);
        dummy.left = root;
        TreeNode curr = dummy;

        while (curr != null) {
            if (curr.left == null) {
                curr = curr.right;
            } else {
                TreeNode prev = curr.left;
                while (prev.right != null && prev.right != curr) {
                    prev = prev.right;
                }

                if (prev.right == null) {
                    prev.right = curr;
                    curr = curr.left;
                } else {
                    reverse(curr.left, prev);
                    TreeNode temp = prev;
                    while (temp != null) {
                        result.add(temp.val);
                        temp = temp.right;
                    }
                    reverse(prev, curr.left);
                    prev.right = null;
                    curr = curr.right;
                }
            }
        }

        return result;
    }

    private void reverse(TreeNode from, TreeNode to) {
        if (from == to) return;
        TreeNode x = from, y = from.right;
        while (x != to) {
            x.right = y.right;
            y.right = x;
            x = y;
            y = y.right;
        }
    }

104. 二叉树的最大深度

解法一、递归 

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null)return 0;
        int leftMax = maxDepth(root.left);
        int rightMax = maxDepth(root.right);
        return Math.max(leftMax,rightMax) + 1;
    }
}

226. 翻转二叉树

解法一、递归

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null)return root;
        invertTree(root.left);
        invertTree(root.right);
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        return root;
    }
}

101. 对称二叉树

解法一、递归

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isS(root.left,root.right);
    }
    private boolean isS(TreeNode left,TreeNode right){
        if(left == null || right == null)return left == right;
        return left.val == right.val && isS(left.left,right.right)&&isS(left.right,right.left);
    }
}

解法二、迭代 

因为List情况下不能add null,所以改换成Queue。不过不改也可以,只需要在null的情况下构建新节点,总之就是改换边界条件

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return isS(root,root);
    }
    private boolean isS(TreeNode left,TreeNode right){
        Queue<TreeNode> res = new LinkedList<>();
        res.add(left);
        res.add(right);
        while (!res.isEmpty()){
            TreeNode u = res.poll();
            TreeNode v = res.poll();
            if (u == null && v == null) {
                continue;
            }
            if ((u == null || v == null) || (u.val != v.val)) {
                return false;
            }
            res.offer(u.left);
            res.offer(v.right);
            res.offer(u.right);
            res.offer(v.left);
        }
        return true;
    }
}

543. 二叉树的直径

解法一、递归

class Solution {
    private int res = 0;
    public int diameterOfBinaryTree(TreeNode root) {
        dfs(root);
        return res;
    }
    private  int dfs(TreeNode root){
        if(root == null)return -1;
        int l = dfs(root.left)+1;
        int r = dfs(root.right)+1;
        res = Math.max(res,l+r);
        return Math.max(l,r);
    }
}

 
102. 二叉树的层序遍历

解法一 层序遍历

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> q = new LinkedList<>();
        List<List<Integer>> res = new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty()){
            Queue<TreeNode> p = q;
            q = new LinkedList<>();
            List<Integer> tmp = new LinkedList<>();
            while(!p.isEmpty()){
                TreeNode node = p.poll();
                if(node == null)continue;
                q.add(node.left);
                q.add(node.right);
                tmp.add(node.val);
            }
            if(!tmp.isEmpty())res.add(tmp);
        }
        return res;
    }
}

108. 将有序数组转换为二叉搜索树

解法一、递归

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        int n = nums.length,mid = n/2;
        return create(nums,0,n);
    }
    private TreeNode create(int[] nums,int x,int y){
        if(x==y)return null;
        int mid = x + (y-x)/2;
        TreeNode node = new TreeNode(nums[mid]);
        node.left = create(nums,x,mid);
        node.right = create(nums,mid+1,y);
        return node;
    }
}

98. 验证二叉搜索树

解法一、递归

class Solution {
    public boolean isValidBST(TreeNode root) {
        if(root == null)return true;
        return BST(root.left,Long.MIN_VALUE,root.val) && BST(root.right,root.val,Long.MAX_VALUE);
    }
    public boolean BST(TreeNode root,long x,long y) {
        if(root == null)return true;
        if(root.val <= x || root.val >= y )return false;
        return BST(root.left,x,root.val) && BST(root.right,root.val,y);
    }
}

 解法二、中序递增

中序出来的数组一定是递增的,同时,递增数组中序构建也一定是BST

class Solution {
    public boolean isValidBST(TreeNode root) {
       List<Integer> tmp = new LinkedList<>();
       while(root != null){
           if(root.left == null){
               tmp.add(root.val);
               root = root.right;
           }else{
               TreeNode node = root.left;
               while(node.right != null && node.right != root){
                   node = node.right;
               }
               if(node.right == null){
                   node.right = root;
                   root = root.left;
               }else{
                   node.right = null;
                   tmp.add(root.val);
                   root = root.right;
               }
           }
       }
       int n = tmp.size(),num = tmp.get(0);
       for(int i = 1;i < n;i++){
           if(tmp.get(i) <= num)return false;
           num = tmp.get(i);
       }
       return true;
    }
}

230. 二叉搜索树中第 K 小的元素

解法一、中序递增

98的变式。在while里判断一下tmp.size()和k的关系剪枝,可以效率提升一半多。

class Solution {
    public int kthSmallest(TreeNode root, int k) {
       List<Integer> tmp = new LinkedList<>();
       while(root != null){
           if(root.left == null){
               tmp.add(root.val);
               root = root.right;
           }else{
               TreeNode node = new TreeNode();
               while(node.right != null && node.right != root){
                   node = node.right;
               }
               if(node.right == null){
                   node.right = root;
               }else{
                   node.right = null;
                   tmp.add(root.val);
                   root = root.right;
               }
           }
       }
       return tmp.get(k);
    }
}

 解法二、dfs

第一个if是边界,第二个if是剪枝,第三个是答案赋值判断

class Solution {
    private int k,res= 0;
    public int kthSmallest(TreeNode root, int k) {
        this.k = k;
        dfs(root);
       return res;
    }
    private void dfs(TreeNode root){
        if(root==null)return;
        dfs(root.left);
        if(k==0)return;
        if(--k==0)res = root.val;
        dfs(root.right);
    }
}

199. 二叉树的右视图

解法一、递归

class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        Deque<TreeNode> a = new LinkedList<>();
        a.add(root);
        List<Integer> res = new LinkedList<>();
        if(root == null)return res;
        while(!a.isEmpty()){
            Deque<TreeNode> q = a;
            a = new LinkedList<>();
            res.add(q.getLast().val);
            while(!q.isEmpty()){
                TreeNode node = q.pollLast();
                if(node.right != null)a.addFirst(node.right);
                if(node.left != null)a.addFirst(node.left);
            }
        }
        return res;
    }
}


105. 从前序与中序遍历序列构造二叉树


 

解法一、递归

靠前序确定节点 靠中序确定左右树 从顶至下递归进行

两个改进:①搜索改进,甚至使用哈希表O(1)。②更改函数传入,l和r,避免复制数组的开销

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        if(n==0)return null;
        int index = findNum(inorder,preorder[0]);
        int [] l = Arrays.copyOfRange(inorder,0,index);
        int [] r = Arrays.copyOfRange(inorder,index+1,n);
        int [] pre1 = Arrays.copyOfRange(preorder,1,1+index);
        int [] pre2 = Arrays.copyOfRange(preorder,1+index,n);
        TreeNode left = buildTree(pre1,l);
        TreeNode right = buildTree(pre2,r);
        return new TreeNode(preorder[0],left,right);
    }
    public int findNum(int[] nums,int num){
        int n = nums.length;
        for(int i = 0;i < n;i++){
            if(nums[i] == num)return i;
        }
        return -1;
    }
}

437. 路径总和 III

解法一、 递归 哈希

务必恢复现场

class Solution {
    private int ans;
    public int pathSum(TreeNode root, int targetSum) {
        Map<Long,Integer>cnt = new HashMap<>();
        cnt.put(0L,1);
        dfs(root,0,targetSum,cnt);
        return ans;
    }
    private void dfs(TreeNode root,long s,int targetSum,Map<Long,Integer> cnt){
        if(root == null)return;
        s+= root.val;
        ans += cnt.getOrDefault(s - targetSum, 0);
        cnt.merge(s,1,Integer::sum);
        dfs(root.left,s,targetSum,cnt);
        dfs(root.right,s,targetSum,cnt);
        cnt.merge(s,-1,Integer::sum);
    }
}

236. 二叉树的最近公共祖先

解法一、递归找路径,判断两条路径共同开头

你根本无法理解这个到底有多慢jpg

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        List<TreeNode> l = new LinkedList<>();
        List<TreeNode> r = new LinkedList<>();
        dfs(root,p,l);
        dfs(root,q,r);
        int n = l.size(),m = r.size(),x = 0,y = 0;
        while(x < n && y < m && l.get(x) == r.get(y)){
            x++;
            y++;
        }
        TreeNode res;
        if(x>=n)res = l.get(n-1);
        else if(y>=m)res = r.get(m-1);
        else res = l.get(x-1);
        return res;
    }
    public boolean dfs(TreeNode root,TreeNode p,List<TreeNode> list){
        if(root == null)return false;
        list.add(root);
        if(root == p){
            return true;
        }
        //都是错的才remove
        if(dfs(root.left,p,list) || dfs(root.right,p,list))return true;
        list.remove(list.size()-1);
        return false;
    }
}

 解法二、递归

进行了一个很大的剪枝。都=null即都没查到,两个都非null即当前节点就公共,p在q下面则返回q即可。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q)return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left != null && right != null)return root;
        return left != null ? left : right;
    }

}

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

解法一、递归

class Solution {
    private int res = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
        dfs(root);
        return res;
    }
    private int dfs(TreeNode root){
        if(root == null)return 0;
        int left = dfs(root.left);
        int right = dfs(root.right);
        res = Math.max(left+right+root.val,res);
        return Math.max(0,Math.max(left+root.val,right+root.val));
    } 
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2306028.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式项目:STM32刷卡指纹智能门禁系统

本文详细介绍基于STM32的刷卡指纹智能门禁系统。 获取资料/指导答疑/技术交流/选题/帮助&#xff0c;请点链接&#xff1a; https://gitee.com/zengzhaorong/share_contact/blob/master/stm32.txt 1 系统功能 1.1 功能概述 本系统由STM32硬件端&#xff08;下位机&#xff09;…

短剧小程序系统源码

短剧小程序系统源码 今天我要向大家介绍的是最新作品——短剧小程序系统源码。这不仅仅是一款简单的播放工具&#xff0c;它背后蕴含的强大功能能够帮助你的短剧业务实现质的飞跃&#xff01; 为什么说这款源码很厉害&#xff1f; 首先&#xff0c;在当今竞争激烈的市场环境…

C#中级教程(2)——走进 C# 面向对象编程:从基础到进阶的深度探索

一、为什么选择面向对象编程 在软件开发的演进过程中&#xff0c;随着程序规模和复杂度的不断增加&#xff0c;传统的编程方式逐渐暴露出局限性。面向对象编程应运而生&#xff0c;它就像是一位智慧的组织者&#xff0c;将程序中的功能进行模块化划分。每个模块各司其职&#x…

基于SpringBoot的“流浪动物救助系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“流浪动物救助系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能结构图 局部E-R图 系统首页界面 系统…

基于WebRTC与AI大模型接入EasyRTC:打造轻量级、高实时、强互动的嵌入式音视频解决方案

随着物联网和嵌入式技术的快速发展&#xff0c;嵌入式设备对实时音视频通信的需求日益增长。然而&#xff0c;传统的音视频解决方案往往存在体积庞大、实时性差、互动体验不佳等问题&#xff0c;难以满足嵌入式设备的资源限制和应用场景需求。 针对以上痛点&#xff0c;本文将介…

Windows - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式

Windows(奇思妙想) - 通过ssh打开带有图形界面的程序 - 一种通过计划任务的曲折实现方式 前言 Windows启用OpenSSH客户端后就可以通过SSH的方式访问Windows了。但是通过SSH启动的程序&#xff1a; 无法显示图形界面会随着SSH进程的结束而结束 于是想到了一种通过执行“计划…

RT-Thread+STM32L475VET6——USB鼠标模拟

文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…

计算机毕业设计SpringBoot+Vue.js母婴商城(源码+LW文档+PPT+讲解+开题报告)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Teigha(ODA<Open Design Alliance>_开放设计联盟)——cad c# 二次开发

需将dll库文件与exe文件放同一路径下&#xff0c;运行exe即可执行。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Thread…

idea 部署 AJ-Report 启动的注意事项

AJ-Report 入门参考&#xff1a; AJ-Report 初学(入门教程) gitee 下载&#xff1a;https://gitee.com/anji-plus/report/releases 根据上面提供的 gitee 下载链接&#xff0c;点击直接下载 最上面的就是最新版本的&#xff0c;旧版本往下拉就可以找到&#xff0c;有三个下载…

智能化客户行为轨迹分析:AI视频监控在大型商场的技术方案

项目背景&#xff1a;为了提升顾客体验并支持精准营销&#xff0c;卖场或商场需要通过智能化手段分析客户在商场内的行为路线。 一、具体需求 1、行为路径分析&#xff1a;跟踪顾客在商场内的移动轨迹&#xff0c;了解顾客的购物习惯和偏好。 2、高频活动区域识别&#xff1a…

Denoising Diffusion Restoration Models论文解读

论文要点 恢复的线性逆问题可以使用预训练的DDPM完成&#xff1a;1. 将降质矩阵使用SVD&#xff0c;得到分解矩阵&#xff1b;2. 使用分解矩阵将图像投影到降质类型间共享的谱空间&#xff1b;3. 谱空间中执行DDPM。 评价 同Track的方法同样很多&#xff0c;比如后续的DDNM、…

基于SpringBoot的校园消费点评管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【NLP 38、激活函数 ④ GELU激活函数】

别盲目&#xff0c;别着急&#xff0c;慢慢走&#xff0c;没事的 —— 25.2.24 一、定义与数学表达式 GELU&#xff08;Gaussian Error Linear Unit&#xff0c;高斯误差线性单元&#xff09;是一种结合概率分布的非线性激活函数&#xff0c;其核心思想是通过输入值服从标准正…

QT:paintEvent、QPainter、QPaintDevice

paintEvent 介绍 在 Qt 编程中&#xff0c;paintEvent 是 QWidget 类中的一个非常重要的虚函数&#xff0c;用于处理绘图事件。当一个 QWidget 或其派生类的实例需要进行重绘操作时&#xff0c;Qt 会自动调用该控件的 paintEvent 函数。 触发时机 窗口首次显示&#xff1a;当…

OpenHarmony-4.基于dayu800 GPIO 实践(2)

基于dayu800 GPIO 进行开发 1.DAYU800开发板硬件接口 LicheePi 4A 板载 2x10pin 插针&#xff0c;其中有 16 个原生 IO&#xff0c;包括 6 个普通 IO&#xff0c;3 对串口&#xff0c;一个 SPI。TH1520 SOC 具有4个GPIO bank&#xff0c;每个bank最大有32个IO&#xff1a;  …

HTML项目一键打包工具:HTML2EXE 最新版

HTML2EXE 工具可以一键打包生成EXE可执行文件。可以打包任意HTML项目或者是一个网址为单个EXE文件&#xff0c;直接打开即可运行。支持KRPano全景VR项目、WebGL游戏项目、视频播放、,课件打包、网址打包等。 下载地址&#xff1a; 最新版HTML2EXE首次发布下载地址 一、功能特点…

BGP配置华为——路径优选验证

实验拓扑 实验要求 实现通过修改AS-Path属性来影响路径选择实现通过修改Local_Preference属性来影响路径选择实现通过修改MED属性来影响路径选择实现通过修改preferred-value属性来影响路径选择 实验配置与效果 1.改名与IP配置 2.as300配置OSPF R3已经学到R2和R4的路由 3.…

深度学习基础--ResNet网络的讲解,ResNet50的复现(pytorch)以及用复现的ResNet50做鸟类图像分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 如果说最经典的神经网络&#xff0c;ResNet肯定是一个&#xff0c;这篇文章是本人学习ResNet的学习笔记&#xff0c;并且用pytorch复现了ResNet50&…

TMDS视频编解码算法

因为使用的是DDR进行传输&#xff0c;即双倍频率采样&#xff0c;故时钟只用是并行数据数据的5倍&#xff0c;而不是10倍。 TMDS算法流程&#xff1a; 视频编码TMDS算法流程实现&#xff1a; timescale 1 ps / 1ps //DVI编码通常用于视频传输&#xff0c;将并行数据转换为适合…