分治的思想(力扣965、力扣144、牛客KY11)

news2024/12/5 3:30:33

引言

分治思想是将问题分解为更小子问题,分别解决后再合并结果。二叉树中常用此思想,因其结构递归,易分解为左右子树问题,递归解决后合并结果。

这篇文章会讲解用分治的思想去解决二叉树的一些题目,顺便会强调在做二叉树的题过程中我容易出错的地方。

单值二叉树:力扣965

我们来看一个题目,这个题就用到了分治的思想:

题目链接:965. 单值二叉树 - 力扣(LeetCode)

7605f75e223e4bdb9247a9441312bd20.png

要想检查一棵树里所有节点的值是否相等,最简单的方式是把每个节点挨个挨个遍历一遍,看看每个节点的值是否与孩子节点(孩子节点不为空的情况下)的值相等。但是这就没有用到分治的思想了。

如何通过分治的思想来解决问题呢?把大问题拆成很多个小问题。求一棵树里所有节点的值是否相等(大问题),就是求左右子树里节点的值是否与根节点的值相等(小问题)。

bool isUnivalTree(struct TreeNode* root) {
    if(root==NULL){
        return true;
    }
    if((root->left&&root->val!=root->left->val)||(root->right&&root->val!=root->right->val))
    {
        //检查左右孩子的值是否与根的值相等
        return false;
    }
    return isUnivalTree(root->left)&&isUnivalTree(root->right);
}

二叉树的前序遍历:力扣144

如果学过二叉树的基础知识掌握的比较好,那它的前序遍历对你来说就是小菜一碟。那为什么这里还要把它拿出来讲解呢?我们先来看一下这道题:144. 二叉树的前序遍历 - 力扣(LeetCode)

我们发现,这道题比我们平时实现的二叉树的前序遍历又额外提了一个要求:将节点的值按照前序遍历的顺序存放在数组中,并将这个数组作为返回值返回。

额外补充一句:在力扣中,如果要求我们返回数组,那我们需要记录它的数组大小。在这个题中,preOrderTraversal函数中的第二个参数returnSize记录的就是最后要返回数组的大小。

分析

其实,只要掌握了二叉树的前序遍历,就算是把里面节点的值按照前序遍历的顺序存放在数组中也不难,但是里面我们有些点需要注意:

首先,我们需要先计算出二叉树中有几个节点,这样我们才好根据节点个数来开辟数组。

附上代码:

int treeSize(struct TreeNode* root)
{
	if (root == NULL) {
		return 0;
	}
	return treeSize(root->left) + treeSize(root->right) + 1;
}

需要注意的问题

然后,我们要再弄一个进行前序遍历的函数,每遍历到一个节点就把它存进数组。

易错代码:

void preOrder(struct TreeNode* root,int* a,int i)
{
    if(root==NULL){
        return;
    }
    a[i++]=root->val;
    preOrder(root->left,a,i);
    preOrder(root->right,a,i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int size=treeSize(root),i=0;
    int* a=(int*)malloc(sizeof(int)*size);
    preOrder(root,a,i);
    *returnSize=i;
    return a;
}

这段代码中存在一些问题,特别是在递归函数 preOrder 中对索引 i 的处理上。

问题分析:

1.索引传递问题: 在 preOrder 函数中,索引 i 是以值传递的方式传递的。这意味着每次递归调用 preOrder 时,都会创建一个新的 i 的副本,而这个副本在递归调用结束后就会被销毁。因此,递归调用中的 i++ 操作并不会影响到外层调用中的 i 值。

举个例子,当 preOrder 第一次被调用时,i 的值是 0。在将根节点的值存入数组后,i 被增加到 1,但这个增加的 i 只在当前函数栈帧中有效。当递归调用左子树或右子树时,i 又会重新从 0 开始,这显然是不正确的。

2.数组大小问题: 虽然数组 a 的大小是通过 treeSize 函数正确计算出来的,但由于索引传递的问题,最终可能并不会填满整个数组。实际上,由于每次递归调用都使用了一个新的 i 副本,所以可能只会在数组的第一个位置存储值。
3.返回大小问题: 由于索引 i 没有正确传递和更新,*returnSize 最终会被设置为一个错误的值。这意味着调用者无法知道实际存储了多少个节点值。

解决方案:

要解决这个问题,需要确保索引 i 在递归调用中能够正确传递和更新:

  • 使用指针传递索引:将 i 的地址传递给 preOrder 函数,这样函数就可以直接修改 i 的值了。

有些人会想到用静态变量或全局变量的做法,但是这里不推荐,这种方法虽然可以工作,但会使函数变得不那么通用和可重用。

正确代码:

void preOrder(struct TreeNode* root,int* a,int* pi)
{
    if(root==NULL){
        return;
    }
    a[(*pi)++]=root->val;
    preOrder(root->left,a,pi);
    preOrder(root->right,a,pi);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize) {
    int size=treeSize(root),i=0;
    int* a=(int*)malloc(sizeof(int)*size);
    preOrder(root,a,&i);
    *returnSize=i;
    return a;
}

二叉树遍历:牛客KY11

题目链接:二叉树遍历_牛客题霸_牛客网

这个题目要求我们根据一串二叉树先序遍历字符串建立链式存储的二叉树,其中#代表该节点为空节点。

分析

我们先根据题目中给出的示例1将二叉树还原出来:abc##de#g##f###

79831e2ce09a45498d384f77c81cc41a.png

结合还原的过程,我们看一下如何通过遍历前序遍历字符串来还原二叉树:

先序遍历的特点是“根左右”,即先访问根节点,再访问左子树,最后访问右子树。

当我们遍历前序遍历字符串时,遇到 # 则返回 NULL,否则创建新节点并递归构建左右子树。

但这里有一个点需要注意,与上一道题中遍历数组时更新索引是一个问题。为了保证索引的正确传递和更新,我们需要往函数中传入索引的地址。

附上代码:

#include <stdio.h>
 
typedef struct binaryTreeNode{
    struct binaryTreeNode* left,*right;
    char val;
}BTNode;
BTNode* createTree(char* a,int* pi)
{
    if(a[(*pi)]=='#'){
        (*pi)++;
        return NULL;
    }
    BTNode* node=(BTNode*)malloc(sizeof(node));
    if(node==NULL){
        perror("malloc fail");
        return NULL;
    }
    node->val=a[(*pi)++];
    node->left=createTree(a, pi);
    node->right=createTree(a, pi);
    return node;
}
void inOrder(BTNode* root)
{
    if(root==NULL){
        return;
    }
     
    inOrder(root->left);
    printf("%c ",root->val);
    inOrder(root->right);
}
int main() {
    char a[100];
    scanf("%s",a);
    int i=0;
    BTNode* tree=createTree(a, &i);
    inOrder(tree);
    return 0;
}

 

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

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

相关文章

中国电信张宝玉:城市数据基础设施建设运营探索与实践

11月28日&#xff0c;2024新型智慧城市发展创新大会在山东青岛召开&#xff0c;中国电信数字政府研究院院长张宝玉在大会发表主旨演讲《城市数据基础设施运营探索与实践》。报告内容包括城市数据基础设施的概述、各地典型做法及发展趋势建议三个方面展开。 篇幅限制&#xff0…

【论文阅读】Federated learning backdoor attack detection with persistence diagram

目的&#xff1a;检测联邦学习环境下&#xff0c;上传上来的模型是不是恶意的。 1、将一个模型转换为|L|个PD,&#xff08;其中|L|为层数&#xff09; 如何将每一层转换成一个PD&#xff1f; 为了评估第&#x1d457;层的激活值&#xff0c;我们需要&#x1d450;个输入来获…

深度学习案例:ResNet50模型+SE-Net

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 回顾ResNet模型 ResNet&#xff0c;即残差网络&#xff0c;是由微软研究院的Kaiming He及其合作者于2015年提出的一种深度卷积神经网络架构。该网络架构的核心创新在于引入了“残差连接”&…

js高级-ajax封装和跨域

ajax简介及相关知识 原生ajax AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML&#xff0c;就是异步的 JS 和 XML。 通过 AJAX 可以在浏览器中向服务器发送异步请求&#xff0c;最大的优势&#xff1a;无刷新获取数据。 按需请求&#xff0c;可以提高网站的性能 AJ…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…

如何让控件始终处于父容器的居中位置(父容器可任意改变大小)

前言&#xff1a; 大家好&#xff0c;我是上位机马工&#xff0c;硕士毕业4年年入40万&#xff0c;目前在一家自动化公司担任软件经理&#xff0c;从事C#上位机软件开发8年以上&#xff01;我们在C#开发winform程序的时候&#xff0c;有时候需要将一个控件居中显示&#xff0c…

Python 调用 Umi-OCR API 批量识别图片/PDF文档数据

目录 一、需求分析 二、方案设计&#xff08;概要/详细&#xff09; 三、技术选型 四、OCR 测试 Demo 五、批量文件识别完整代码实现 六、总结 一、需求分析 市场部同事进行采购或给客户报价时&#xff0c;往往基于过往采购合同数据&#xff0c;给出现在采购或报价的金额…

【QT】背景,安装和介绍

TOC 目录 背景 GUI技术 QT的安装 使用流程 QT程序介绍 main.cpp​编辑 Wiget.h Widget.cpp form file .pro文件 临时文件 C作为一门比较古老的语言&#xff0c;在人们的认知里始终是以底层&#xff0c;复杂和高性能著称&#xff0c;所以在很多高性能需求的场景之下…

Linux内核编译流程(Ubuntu24.04+Linux Kernel 6.8.12)

万恶的拯救者&#xff0c;使用Ubuntu没有声音&#xff0c;必须要自己修改一下Linux内核中的相关驱动逻辑才可以&#xff0c;所以被迫学习怎么修改内核&编译内核&#xff0c;记录如下 准备工作 下载Linux源码&#xff1a;在Linux发布页下载并使用gpg签名验证 即&#xff1a…

【阅读笔记】Android广播的处理流程

关于Android的解析&#xff0c;有很多优质内容&#xff0c;看了后记录一下阅读笔记&#xff0c;也是一种有意义的事情&#xff0c; 今天就看看“那个写代码的”这位大佬关于广播的梳理&#xff0c; https://blog.csdn.net/a572423926/category_11509429.html https://blog.c…

linux下Qt程序部署教程

文章目录 [toc]1、概述2、静态编译安装Qt1.1 安装依赖1.2 静态编译1.3 报错1.4 添加环境变量1.5 下载安装QtCreator 3、配置linuxdeployqt环境1.1 在线安装依赖1.2 使用linuxdeployqt提供的程序1.3 编译安装linuxdeployqt 4、使用linuxdeployqt打包依赖1.1 linuxdeployqt使用选…

【PHP】部署和发布PHP网站到IIS服务器

欢迎来到《小5讲堂》 这是《PHP》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言安装PHP稳定版本线程安全版解压使用 PHP配置配置文件扩展文件路径…

视觉经典神经网络学习01_CNN(1)

一、概述 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种专门用于处理具有网格状结构数据的深度学习模型。最初&#xff0c;CNN主要应用于计算机视觉任务&#xff0c;但它的成功启发了在其他领域应用&#xff0c;如自然语言处理等。…

【golang】单元测试,以及出现undefined时的解决方案

单元测试 要对某一方法进行测试时&#xff0c;例如如下这一简单减法函数&#xff0c;选中函数名后右键->转到->测试 1&#xff09;Empty test file 就是一个空文件&#xff0c;我们可以自己写测试的逻辑 但是直接点绿色箭头运行会出问题&#xff1a; 找不到包。我们要在…

DVWA靶场通关——DOM型XSS漏洞

一、DOM型XSS攻击概述 DOM型XSS&#xff08;DOM-based Cross-Site Scripting&#xff0c;DOM XSS&#xff09;是一种跨站脚本攻击&#xff08;XSS&#xff09;的变种&#xff0c;它与传统的反射型XSS&#xff08;Reflected XSS&#xff09;或存储型XSS&#xff08;Stored XSS&a…

【Unity 动画】设置跟运动(Apply Root)模型跟着动画产生位移

一、导入的动画本身必须有跟随动画产生位移或者旋转的效果 二、导入Unity后 在Unity中&#xff0c;根运动&#xff08;Root Motion&#xff09;是指动画中角色根节点的移动和旋转。根节点通常是角色的根骨骼&#xff08;Root Bone&#xff09;&#xff0c;它决定了角色的整体…

Spring AI 框架介绍

Spring AI是一个面向人工智能工程的应用框架。它的目标是将Spring生态系统的设计原则&#xff08;如可移植性和模块化设计&#xff09;应用于AI领域&#xff0c;并推广使用pojo作为AI领域应用的构建模块。 概述 Spring AI 现在(2024/12)已经支持语言&#xff0c;图像&#xf…

C++小问题

怎么分辨const修饰的是谁 是限定谁不能被改变的&#xff1f; 在C中&#xff0c;const关键字的用途和位置非常关键&#xff0c;它决定了谁不能被修改。const可以修饰变量、指针、引用等不同的对象&#xff0c;并且具体的作用取决于const的修饰位置。理解const的规则能够帮助我们…

近几年,GIS专业的五类就业方向!

近二十几年来&#xff0c;地理信息科学毕业生的就业方向在不断发生变化。 早期的地理信息科学技术主要应用于政府部门&#xff0c;因此学生就业主要在高校、交通运输、规划勘测设计、国土、矿业、水利电力、通讯、农林、城市建设、旅游等国家政府部门或事业单位。 随着地理信…

【Maven】继承和聚合

5. Maven的继承和聚合 5.1 什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置&#xff0c;但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本&#xff0c;且这些模块之间不存在依赖关系&#xff0c;这就导致同一个依赖…