LeetCode算法小抄--花式遍历二叉树

news2024/11/13 9:31:14

LeetCode算法小抄--花式遍历二叉树

    • 花式遍历二叉树
      • 翻转二叉树
        • [226. 翻转二叉树](https://leetcode.cn/problems/invert-binary-tree/)
      • 填充节点的右侧指针
        • [116. 填充每个节点的下一个右侧节点指针](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/)
      • 将二叉树展开为链表
        • [114. 二叉树展开为链表](https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/)

⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3545字,阅读大概需要3分钟
🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号:不懂开发的程序猿
个人网站:https://jerry-jy.co/

花式遍历二叉树

翻转二叉树

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

// 用「遍历」的思维模式
class Solution {
    public TreeNode invertTree(TreeNode root) {
        // 遍历二叉树,交换每个节点的子节点
        traverse(root);
        return root;
    }
    private void traverse(TreeNode root){
        if(root == null) return;
        /**** 前序位置 ****/
        // 每一个节点需要做的事就是交换它的左右子节点 
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;

        // 遍历框架,去遍历左右子树的节点
        traverse(root.left);
        traverse(root.right);
    }
}

可以用 invertTree(x.left) 先把 x 的左子树翻转,再用 invertTree(x.right)x 的右子树翻转,最后把 x 的左右子树交换,这恰好完成了以 x 为根的整棵二叉树的翻转,即完成了 invertTree(x) 的定义。

// 用「分解问题」的思维模式
class Solution {
    // 定义:将以 root 为根的这棵二叉树翻转,返回翻转后的二叉树的根节点
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return null;

        // 利用函数定义,先翻转左右子树
        TreeNode left = invertTree(root.left);
        TreeNode right = invertTree(root.right);

        // 然后交换左右子节点
        root.left = right;
        root.right = left;

        // 和定义逻辑自恰:以 root 为根的这棵二叉树已经被翻转,返回 root
        return root;
    }
}

这种「分解问题」的思路,核心在于你要给递归函数一个合适的定义,然后用函数的定义来解释你的代码;如果你的逻辑成功自恰,那么说明你这个算法是正确的。

填充节点的右侧指针

116. 填充每个节点的下一个右侧节点指针

给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}

填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL

初始状态下,所有 next 指针都被设置为 NULL

在这里插入图片描述

很容易写出以下代码:

// 错误的,因为它只能把相同父节点的两个节点穿起来
class Solution {
    public Node connect(Node root) {
        traverse(root);
        return root;
    }
    private void traverse(Node root){
        if(root == null || root.left == null) return;

        // 把左子节点的 next 指针指向右子节点
        root.left.next = root.right;

        traverse(root.left);
        traverse(root.right);
    }
}

节点 5 和节点 6 不属于同一个父节点,那么按照这段代码的逻辑,它俩就没办法被穿起来

传统的 traverse 函数是遍历二叉树的所有节点,但现在我们想遍历的其实是两个相邻节点之间的「空隙」

所以我们可以在二叉树的基础上进行抽象,你把图中的每一个方框看做一个节点:

在这里插入图片描述

一棵二叉树被抽象成了一棵三叉树,三叉树上的每个节点就是原先二叉树的两个相邻节点

现在,我们只要实现一个 traverse 函数来遍历这棵三叉树,每个「三叉树节点」需要做的事就是把自己内部的两个二叉树节点穿起来

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        if(root == null) return null;
        traverse(root.left, root.right);
        return root;
    }

    // 三叉树遍历框架
    private void traverse(Node node1, Node node2){
        if(node1 == null || node2 == null) return;

        /**** 前序位置 ****/
        // 将传入的两个节点穿起来
        node1.next = node2;

        // 连接相同父节点的两个子节点
        traverse(node1.left, node1.right);
        traverse(node2.left, node2.right);
        // 连接跨越父节点的两个子节点
        traverse(node1.right, node2.left);
    }
}

将二叉树展开为链表

114. 二叉树展开为链表

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

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

在这里插入图片描述

思路

对于一个节点 x,可以执行以下流程:

1、先利用 flatten(x.left)flatten(x.right)x 的左右子树拉平。

2、将 x 的右子树接到左子树下方,然后将整个左子树作为右子树。

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    // 定义:将以 root 为根的树拉平为链表
    public void flatten(TreeNode root) {
        // base case
        if(root == null) return;

        // 利用定义,把左右子树拉平
        flatten(root.left);
        flatten(root.right);

        /**** 后序遍历位置 ****/
        // 1、左右子树已经被拉平成一条链表
        TreeNode left = root.left;
        TreeNode right = root.right;

        // 2、将左子树作为右子树
        root.left = null;
        root.right = left;

        // 3、将原先的右子树接到当前右子树的末端
        TreeNode p = root;
        while(p.right != null){
            p = p.right;
        }
        p.right = right;
    }

}

总结

二叉树解题的思维模式分两类:

1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。

2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

–end–

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

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

相关文章

OpenCV实例(一)人脸检测

OpenCV实例(一)人脸检测 1.人脸检测和识别概述2.使用OpenCV进行人脸检测2.1静态图像中的人脸检测2.2视频中的人脸检测 作者:Xiou 1.人脸检测和识别概述 计算机视觉使很多任务成为现实,其中两项任务就是人脸检测(在图…

psql Centos7安装postgresql-12

之前在centos7上下的postgresql,它的数据库实例在 “var/lib/pgsql/” 下。这就导致了系统用户的"postgres"的家目录跟postgresql数据库目录不在同一目录下。因此,今天趁着有闲暇时间把数据库装到"postgres"目录下,顺便把…

罗丹明荧光染料标记叶酸,FA-PEG2000-RB,叶酸-聚乙二醇-罗丹明; Folic acid-PEG-RB

FA-PEG-RB,叶酸-聚乙二醇-罗丹明 中文名称:叶酸-聚乙二醇-罗丹明 英文名称:FA-PEG-RB, Folic acid-PEG-RB 性状:粉红色固体或液体,取决于分子量 溶剂:溶于水和DMSO、DMF等常规性有机溶剂 保存条件:-2…

学习系统编程No.17【vscode实战】

引言: 北京时间:2023/4/11/7:25,昨天11点洗澡,洗完直接睡,导致现在头发愈发不能看,So,平头时刻将要来临,头发太长真的很不方便,昨天已经更文啦!这个星期一定…

miss_01(简单密码学及音频隐写)

下载附件,解压时提示输入密码 使用010editor打开,发现deFlags值被修改 (如果frFlags 或者 deFlags 的值不为0就会导致zip的伪加密) 将deFlags的值修改为0,并将文件另存为1.zip 再次打开,没有密码提示了 打…

酒吧攻略:一文解读酒吧类型

目前主流酒吧类型可以大致分为以下几类: 夜店:(NIGHT CLUB):KTV,夜总会,酒吧等总称club,主要指的就是夜店。 Bar:多指娱乐休闲类的酒吧,提供现场的乐队或歌…

UG导出点集坐标到txt文本文档中

文章目录 前言一、下载文件二、使用步骤1.运行Grip程序2.选择下载的points-file.grx文件3.选择要导出的文本文档的位置4.选择想要导出的点集5.查看文件 参考 前言 将UG中的离散的点或者点集坐标导出到文本文档; 原文地址 俩文件链接如下,失效了可以私信…

客快物流大数据项目(一百一十四):负载均衡 Spring Cloud Ribbon

文章目录 负载均衡 Spring Cloud Ribbon 一、Ribbon 简介 二、负载均衡源码跟踪探究 负载均衡 Spring Cloud Ribbon 为了增加服务并发访问量,我们搭建集群,集群的负载均衡怎么实现?

OpenAI-ChatGPT最新官方接口《速率并发限制》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(八)(附源码)

Rate limits 速率并发限制前言Introduction 导言What are rate limits? 什么是速率限制?Why do we have rate limits? 为什么我们有速率限制?What are the rate limits for our API? 我们API的速率限制是什么?GPT-4 rate limits GPT-4速率…

【JavaEE】Spring + IoC + DI

目录 Spring概念 IoC DI Spring概念 Spring是包含众多工具方法的IoC容器。 IoC IoC:Inversion of Control 控制权反转 它是一种思想,是面向对象的一种设计原则。这种思想为了实现类与类之间的解耦。 比如当一个对象要使用另一个对象时,不再…

IO流相关知识

IO流 1.文件 保存数据的地方 2.文件流 文件在程序中以流的形式来操作的 流:数据在数据源(文件)和程序(内存)之间的经历的路程 输入流:数据从数据源(文件)到程序(内存…

【FPGA-DSP】第五期:FFT调用流程

目录 1. matlab输入信号编写 2. Simulink开发 2.1 模块搭建 2.2 Simulink运行 2.3 matlab信号处理 拓:输入信号位数改变 本章节主要说明如何在system generator中使用fft模块,话不多说,看操作: 参考教程第5期 - FFT调用流…

PyQt PyQt5 Python VTK Gui Actor 选中 高亮显示 actor

前言: 本文主要介绍了如何使用Python VTK高亮显示actor,使用Python语言,高亮显示选中的actor。当窗口中的圆球actor被选中时,会变成红色,并且会显示actor三遍面片边缘信息。 效果: VTK VTK,&…

Linux常见实用操作汇总(带示例版)

Linux常见实用操作汇总 1、各类快捷键1.1 强制停止1.2 退出、登出1.3 历史命令搜索1.4 光标移动1.5 清屏 2、软件安装2.1 在CentOS系统中,使用yum命令联网管理软件安装2.2 在Ubuntu系统中,使用apt命令联网管理软件安装。 3、systemctl4、软连接5、日期和…

Golang每日一练(leetDay0036) 二叉树专题(5)

目录 106. 从中序与后序遍历序列构造二叉树 Construct-binary-tree-from-inorder-and-postorder-traversal 🌟🌟 107. 二叉树的层序遍历 II Binary Tree Level-order Traversal II 🌟🌟 108. 将有序数组转换为二叉搜索树 C…

Nginx配置ssl证书实现https安全访问

目录 一、Nginx的安装与配置 安装步骤 二、SSL证书获取 三、Nginx配置 前题条件,拥有服务器与可以解析到该服务器的自己的域名。 一、Nginx的安装与配置 若已安装好了Nginx,则需查看自己的Nginx是否开启了SSL的模块功能: ./nginx -V 显…

多媒体信息发布系统解决方案

1.系统概述 多媒体信息发布系统主要是一个用于发布各种信息的平台,包括文字、图片、音频和视频等多种形式的信息。该系统旨在满足用户的信息需求,为信息发布者提供一个高效、安全、可靠的信息发布平台。 2.系统模块 (1)用户管理…

爬虫攻守道 - 猿人学第20题 - 殊途同归

写在开头 这题也是,自己搞顶多追踪到wasm代码,然后就走不下去了。找了2个参考方案,自己做的过程中还又遇到些新的问题,下面做个记录。解法1参考文章解法2参考文章 解法1:追根溯源 在 JS 代码中追踪到 Payload 赋值位…

漂亮实用的15个脑图模板,你知道哪些是AI做的吗?

对于很多第一次接触到思维导图的朋友,看到软件的时候往往找不到方向,不知道如何创作? 今天大家的好助手来了。 一是有大量的思维导图模板,大家看着模板做,慢慢就会做了。 二是ProcessOn 思维导图已经可以用AI 做思维…

鏖战大模型,未必能拯救商汤

在不被资本市场看好的质疑声中,商汤科技于近日跟风推出了自己的大模型产品,而且还直接打造了一个大模型超市,声称包括CV(计算机视觉)、NLP(​​​​​​​自然语言处理)、AIGC(人工智…