力扣每日一题99:恢复二叉搜索树

题目

给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 

示例 1:

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

示例 2:

输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。

提示:

  • 树上节点的数目在范围 [2, 1000] 内
  • -231 <= Node.val <= 231 - 1

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗?

通过次数

146.4K

提交次数

242.3K

通过率

60.5%

分析

二叉搜索树中序遍历是有序的(a[i]<a[i+1]),错误交换两个节点后,存在两个地方(a[i]>a[i+1]),如果两个地方重复了,那就是一个地方。

所以我们只要根据a[i]>a[i+1]这一特性找的错误交换的两个点换回来就行了。

普通方法:设置数组存放数据。时间O(N),空间O(N)

中序遍历依次二叉树,同时将每个节点的地址和值分别放在一个数组里。然后再遍历记录数值的数组,找到要交换的两个位置。

class Solution {
public:void dfs(int arr[],TreeNode* adress[],int &pos,TreeNode* root){if(!root) return;dfs(arr,adress,pos,root->left);arr[pos]=root->val;adress[pos]=root;pos++;dfs(arr,adress,pos,root->right);}void recoverTree(TreeNode* root) {TreeNode *adress[1000];int arr[1000];int pos=0;dfs(arr,adress,pos,root);int t1=-1,t2=0;for(int i=0;i<pos-1;i++){//cout<<arr[i]<<",";if(arr[i]>arr[i+1]){if(t1==-1){t1=i;t2=i+1;}else t2=i+1;}}//cout<<arr[pos-1];//cout<<"\nt1="<<t1<<"   t2="<<t2;int t=adress[t1]->val;adress[t1]->val=adress[t2]->val;adress[t2]->val=t;}
};

进阶:中序遍历,栈记录前驱。时间O(N),空间(H),H为树的高度。

前面的方法是找到要交换连个节点的地址,然后交换值。我们用了一个数组记录所有节点的地址。其实我们就交换两个数,记录两个地址就行了。用二叉树的迭代法遍历可以用栈存放遍历的前驱,刚好符合了i和i+1的关系。下面是官方题解。

class Solution {
public:void recoverTree(TreeNode* root) {stack<TreeNode*> stk;TreeNode* x = nullptr;TreeNode* y = nullptr;TreeNode* pred = nullptr;while (!stk.empty() || root != nullptr) {while (root != nullptr) {stk.push(root);root = root->left;}root = stk.top();stk.pop();if (pred != nullptr && root->val < pred->val) {y = root;if (x == nullptr) {x = pred;}else break;}pred = root;root = root->right;}swap(x->val, y->val);}
};

高阶:Morris遍历,时间O(N),空间O(1)

废话不多说,看官方题解的代码。

class Solution {
public:void recoverTree(TreeNode* root) {TreeNode *x = nullptr, *y = nullptr, *pred = nullptr, *predecessor = nullptr;while (root != nullptr) {if (root->left != nullptr) {// predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止predecessor = root->left;while (predecessor->right != nullptr && predecessor->right != root) {predecessor = predecessor->right;}// 让 predecessor 的右指针指向 root,继续遍历左子树if (predecessor->right == nullptr) {predecessor->right = root;root = root->left;}// 说明左子树已经访问完了,我们需要断开链接else {if (pred != nullptr && root->val < pred->val) {y = root;if (x == nullptr) {x = pred;}}pred = root;predecessor->right = nullptr;root = root->right;}}// 如果没有左孩子,则直接访问右孩子else {if (pred != nullptr && root->val < pred->val) {y = root;if (x == nullptr) {x = pred;}}pred = root;root = root->right;}}swap(x->val, y->val);}
};

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle-数据库迁移之后性能变慢问题分析

问题背景&#xff1a; ​一套Oracle11.2.0.4的RAC集群&#xff0c;通过Dataguard switchover方式迁移到新机器之后&#xff0c;运行第一天应用报障说应用性能慢&#xff0c;需要进行性能问题排查 问题分析&#xff1a; 首先&#xff0c;登陆到服务器&#xff0c;用TOP看一眼两个…

常用Java Lambda表达式示例

文章目录 1. **实现Runnable接口**&#xff1a;2. **事件监听器**&#xff08;如Swing中的ActionListener&#xff09;&#xff1a;3. **集合遍历**&#xff08;使用forEach方法&#xff09;&#xff1a;4. **过滤集合**&#xff08;使用Stream API&#xff09;&#xff1a;5. …

Prometheus-AlertManager 邮件告警

环境,软件准备 本次演示环境&#xff0c;我是在虚拟机上安装 Linux 系统来执行操作&#xff0c;以下是安装的软件及版本&#xff1a; System: CentOS Linux release 7.6Docker: 24.0.5Prometheus: v2.37.6Consul: 1.6.1 docker 安装prometheus,alertmanage,说明一下这里直接将…

WIN10自带查看硬盘运行时间的指令

#创作灵感# 之前一直在捣腾电脑&#xff0c;最近又搞了个R720XD&#xff08;后续会有分享&#xff09;&#xff0c;所以对硬盘比较关注&#xff0c;查了一下硬盘方面的一些坑&#xff0c;机械硬盘最关注的问题就是运行时间了。 #正文# 查看硬盘运行时间需要用到Get-Disk指令&a…

(学习打卡2)重学Java设计模式之六大设计原则

前言&#xff1a;听说有本很牛的关于Java设计模式的书——重学Java设计模式&#xff0c;然后买了(*^▽^*) 开始跟着小傅哥学Java设计模式吧&#xff0c;本文主要记录笔者的学习笔记和心得。 打卡&#xff01;打卡&#xff01; 六大设计原则 &#xff08;引读&#xff1a;这里…

Vue 中的 ref 与 reactive:让你的应用更具响应性(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Android14之audit2allow自动生成Selinux规则(一百七十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Intellij IDEA 快速开发参考

快捷键 核心快捷键 IntelliJ IDEA 作为一个以快捷键为中心的 IDE&#xff0c;为大多数操作建议了键盘快捷键。在这个主题中&#xff0c;您可以找到最不可缺少的列表&#xff0c;使 IntelliJ IDEA 轻松实现第一步。 核心快捷键表&#xff1a; 操作快捷键根据名称查找操作CtrlSh…

贪心算法part05 435无重叠区间

435无重叠区间 763 划分字母区间 56合并区间

为什么JAVA_HOME修改后Java版本不变

今天的实验需要对java project进行降版本后重构。于是去Oracle官网下载了jdk1.7。然后将系统环境变量JAVA_HOME改成了安装后的jdk1.7路径。即 C:\Program Files\Java\jdk1.7.0_80 系统变量Path中直接引用了%JAVA_HOME%\bin。 但是当我查看版本&#xff0c;却出现了javac改了…

新版selenium4.0 + Python使用详解

1、selenium简介 Selenium是一个用于Web应用程序测试的工具&#xff0c;Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。支持的浏览器包括IE&#xff08;7, 8, 9, 10, 11&#xff09;&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Google…

基于ssm的资产管理信息系统+vue论文

摘要 当下&#xff0c;正处于信息化的时代&#xff0c;许多行业顺应时代的变化&#xff0c;结合使用计算机技术向数字化、信息化建设迈进。以前企业对于资产信息的管理和控制&#xff0c;采用人工登记的方式保存相关数据&#xff0c;这种以人力为主的管理模式已然落后。本人结…