从零学算法(剑指 Offer 33)

2023-09-18 16:28:36

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:

     5
    / \
   2   6
  / \
 1   3

示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true

  • 我的思路:二叉搜索树就是左节点都小于根节点,右节点都大于根节点,子树同样满足该条件。那么不难想到,递归部分就是不断分出一棵棵子树判断是否符合左小右大的特点。入参当然就是代表一棵子树的数组的起止下标。由于是后序遍历,所以右边界就是根节点。如果有边界小于左边那说明子树都判断完了,竟然在这之前都没返回 false 那只能返回 true 了。然后定义一个下标从右边界开始往前找,如果有比根节点小的,说明从右子树找到了左子树了,此时的下标就是左子树的右边界,遍历的过程其实相当于把右子树都找完了,继续往前遍历这个下标,等于遍历左子树,判断是否都小于根节点即可,然后继续判断划分出的左右子树
  •   int[] pos;
      public boolean verifyPostorder(int[] postorder) {
          this.pos=postorder;
          return dfs(0,pos.length-1);
      }
      // root 也可以理解为 right,因为是后序遍历数组
      public boolean dfs(int left,int root){
          if(root < left)return true;
          // 找到第一个小于根节点的下标,这就是左子树的右边界
          int firsetLess = root-1;
          while(firsetLess >=0 && pos[firsetLess]>pos[root]){
              firsetLess--;
          }
          // 遍历左子树
          for(int i = firsetLess;i>=0;i--){
              if(pos[i]>pos[root])return false;
          }
          return dfs(firsetLess+1,root-1) && dfs(left,firsetLess);
      }
    
  • 他人题解1:思路一样,不过代码实现更巧妙一些,他是从前往后找,先默认左子树都正确,然后判断没有直接判断右子树的每个值是否都大于根节点,而是只要大于根节点就往后遍历,让他遍历到根节点为止,如果能够到达根节点,说明的确是都大于根节点,否则自然是有问题了。用最后的下标是否等于根节点来转换了右子树正确性的问题。
  •   public boolean verifyPostorder(int[] postorder) {
          return recur(postorder, 0, postorder.length - 1);
      }
      boolean recur(int[] postorder, int i, int j) {
          if(i >= j) return true;
          int p = i;
          // 划分左子树
          while(postorder[p] < postorder[j]) p++;
          // m,p 为右子树起点 
          int m = p;
          // 只要右子树合法 p 最终就会遍历到根节点,然后 postorder[p] == postorder[j]) 就结束循环了
          while(postorder[p] > postorder[j]) p++;
          // 所以最终结果就是 p 是否等于 j 以及递归进行左右子树的判断
          return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
      }
    
  • 他人题解2:还有一种我似懂非懂的解法,把后序遍历倒序,你会得到根右左的数组,这时遍历该数组,你会先得到一个递增的数组,然后,只要发现有递减的数了,说明到了左子树,那么左子树应该满足所有数都小于根节点。根节点怎么找呢,你会发现,根节点有个特性,根节点一定是大于左节点且最接近左节点的数,比如后序数组为 132,倒序后为 231,之前的 23 都好好的,是升序的,遍历到 1 时说明到左子树了,根节点肯定在前面,所以需要用一个数据结构来存储前面的 23,2 是根,需要使用到它,3 不是根并且由于之后要判断的所有数只要小于根就行,所以之后也用不到它了,需要移除,那么能够满足我们需求的就是使用栈,存储时为 23,遍历时弹出 3 然后弹出 2,此时根节点为 2,之后遍历的数都应该小于 2
  •   public boolean verifyPostorder(int[] postorder) {
          Stack<Integer> stack = new Stack<>();
          // 初始根节点是没有根节点的,所以为了最开始是符合条件的
          // 那么我们就用一定符合条件的最大值默认为他的根节点
          // 因为我们是根据判断左子树来验证是否为搜索树
          // 所以也就等同于我们默认根节点为一个节点的左节点,那这个结点自然是要一个一定大于根节点的数
          int root = Integer.MAX_VALUE;
          for(int i = postorder.length - 1; i >= 0; i--) {
          	// 若当前数大于根节点就有问题了
              if(postorder[i] > root) return false;
              // 只要突然递减了就会进入循环寻找根节点 root
              // 找到找完或者存储的数小于当前节点为止
              // 这也就代表我们找到了最接近当前节点的值并且大于这个值的节点
              // 也就是根节点
              // 也是由于整体趋势是根右左,大体呈现为降序
              // 所以我们顺序遍历的整体趋势也同样是从大往小遍历
              // 所以在验证的过程中 root 也是越来越小的
              while(!stack.isEmpty() && stack.peek() > postorder[i])
                  root = stack.pop();
              // 把点都 push 进去,以备之后寻找 root
              stack.add(postorder[i]);
          }
          return true;
      }
    
  • 建议还是看原文的讲解,我唯一不理解的点就在于左节点永远不是和它的直接根节点比较,而是和爷节点比较,这是怎么验证正确性的
更多推荐

如何利用Java实现 AI 人脸融合特效

Java实现AI人脸融合特效项目背景AI人脸融合特效的原理代码实现第一步:调用token接口人脸融合部分工具类最终效果图项目背景最近自从chat-gpt爆火以来,AI技术在人工智能领域持续迭代的创新,为人们的生活带来了许多震撼的应用。比如其中的,AI人脸融合特效,在各大抖音、B站等平台上,越来越火热,基于这,我也打算利

使用 Next.js、Langchain 和 OpenAI 构建 AI 聊天机器人

在当今时代,将AI体验集成到您的Web应用程序中变得越来越重要。LangChain与Next.js的强大功能相结合,提供了一种无缝的方式来将AI驱动的功能引入您的应用程序。在本指南中,我们将学习如何使用Next.js,LangChain,OpenAILLM和VercelAISDK构建AI聊天机器人。文章目录Langch

细说 Spring Cloud Gateway

1.SpringCloudGateway简介与核心概念在微服务架构中,API网关是一个非常重要的组件,它可以帮助我们实现服务的路由、负载均衡、认证授权等功能。SpringCloudGateway是SpringCloud官方推出的一个基于Spring5、SpringBoot2和ProjectReactor的API网关实现

Linux centOS yum install MySQL5.7

下载并安装MySQLYUM仓库wgethttps://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpmsudoyumlocalinstallmysql57-community-release-el7-11.noarch.rpm这将为您的CentO

PKE 安全性的提升方式:Naor-Yung、Fischlin、Fujisaki-Okamoto

参考文献;[NY90]NaorM,YungM.Public-keycryptosystemsprovablysecureagainstchosenciphertextattacks[C]//Proceedingsofthetwenty-secondannualACMsymposiumonTheoryofcomputin

深入解析Perlin Simplex噪声函数:在C++中构建现代、高效、免费的3D图形背景

引言在计算机图形中,噪声是一个经常被讨论的话题。无论是为了制造自然的纹理,还是为了模拟复杂的现实世界现象,噪声函数都在其中起着关键作用。而在众多噪声函数中,PerlinSimplex噪声无疑是最受欢迎的一种。其原因不仅在于其干净、快速的特性,更因为其所提供的连续性和一致性非常适合图形渲染。本文将为你展示如何在C++中实

8路光栅尺磁栅尺编码器或16路高速DI脉冲信号转Modbus TCP网络模块 YL99-RJ45

特点:●光栅尺磁栅尺解码转换成标准ModbusTCP协议●高速光栅尺磁栅尺4倍频计数,频率可达5MHz●模块可以输出5V的电源给光栅尺或传感器供电●支持8个光栅尺同时计数,可识别正反转●可以设置作为16路独立DI高速计数器●可网页直接查看所有数据无需其他软件●编码器计数值和DI计数都支持断电自动保存●DI输入和网络通信

每天几道Java面试题:集合(第四天)

目录第四幕、第一场)大厦楼下门口第二场)大门口友情提醒背面试题很枯燥,加入一些戏剧场景故事人物来加深记忆。PS:点击文章目录可直接跳转到文章指定位置。第四幕、第一场)大厦楼下门口【面试者老王,门卫甲,门卫乙,面试者奥斯卡】门卫甲:天下熙熙皆为利来,天下攘攘皆为利往,像门卫乙和我这样不为名利专心看门,世界上又有多少人呢?

蓝牙资讯|苹果新款AirPods Pro支持Vision Pro无损音频和IP54防水防尘

苹果公司宣称,USB-C能够带来更多灵活性,现在用户可以使用手机的USB-C接口,为AirPodsPro耳机盒充电。虽然苹果没有详细介绍这款耳机,但在今天的新闻稿中依然透露了一些不一样的地方,例如新款AirPodsPro2升级到了IP54级别(原版不防尘,仅IPX4级抗水),可陪伴用户在恶劣的环境中展开冒险。除此之外,

如何用Java+SpringBoot+Vue构建一个靓车汽车销售网站?

博主介绍:✌全网粉丝30W+,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌🍅文末获取源码联系🍅👇🏻精彩专栏推荐订阅👇🏻不然下次找不到哟2022-2024年最全的计算机软件毕业设计选题

阿里云通义千问大模型正式开放;玩10次ChatGPT就要消耗1升水

🦉AI新闻🚀阿里云通义千问大模型正式开放,已有超20万企业申请接入测试摘要:阿里云通义千问大模型已经通过备案并向公众开放。用户可以登录官网体验,企业用户可以通过阿里云调用API。阿里云通义千问在一个月的邀测中,就有超过20万企业和机构用户申请接入测试,并与OPPO、得物、钉钉、淘宝、浙江大学等合作。此外,阿里云还开

热文推荐