leetcode 99:恢复二叉搜索树

2024-09-02 15:18
文章标签 leetcode 恢复 搜索 二叉 99

本文主要是介绍leetcode 99:恢复二叉搜索树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

方法一:首先使用中序遍历将所有的节点和节点的值存起来,如果是搜索二叉树节点值的数组应该是升序的,找到不是升序的点,交换节点的值,空间复杂度为O(n)

void inorder(TreeNode*root,std::vector<TreeNode*>&list,std::vector<int> &vals){if(root==NULL)return;inorder(root->left,list,vals);list.push_back(root);vals.push_back(root->val);inorder(root->right,list,vals);
}void recoverTree(TreeNode*root){std::vector<TreeNode*>list;std::vector<int>vals;inorder(root,list,vals);std::vector<int> node;for(int i=0;i<vals.size()-1;){if(vals[i]>vals[i+1]){node.push_back(i);i=i+2;if(node.size()==2)break;}elsei=i+1;}if(node.size()==1){int c=node.back();node.clear();list[c]->val=vals[c+1];list[c+1]->val=vals[c];}else if(node.size()==2){int c1=node[0];int c2=node[1];node.clear();list[c1]->val=vals[c2+1];list[c2+1]->val=vals[c1];}sort(vals.begin(),vals.end());for(int i=0;i<list.size();i++)list[i]->val=vals[i];
}

方法二:使用Morris算法进行遍历,空间复杂度为O(1)

首先介绍Morris算法

1. 当前子树的头结点为head,空闲指针由head的左子树中最右结点的右指针指向head结点。对head的左子树重复该步骤1,直到遍历至某个结点没有左子树,将该结点记    为node。进入步骤2。

2. 从node结点开始通过每个结点的右指针进行移动,并打印结点的值。

  假设遍历到的当前结点为curNode,做如下判断:

curNode结点的左子树中最右结点(记为lastRNode)是否指向curNode。

A. 是 让lastRNode结点的右指针指向null,打印curNode的值。接着通过curNode的右指针遍历下一个结点,重复步骤2。

B. 否 将curNode为头结点的子树重复步骤1。

 

下面举例说明上述步骤(先以中序遍历为例),二叉树结构如下图所示:

遍历至结点1 发现其没有左子树 记为Node。

curNode : 1 打印1

curNode : 2 满足A 空闲指针由1的右指针指向2 将该空闲指针取消掉 打印2。通过2的右指针遍历到3。

curNode : 3 满足B 进行步骤1 最终打印3。

通过空闲指针遍历至4。

curNode : 4 满足A 空闲指针由3的右指针指向4 将该空闲指针取消掉 打印4。通过4的右指针遍历到6。

至此 左子树和根结点遍历完毕。

curNode : 6 满足B 进行步骤1 之后二叉树变为右图。

遍历至结点5 其没有左子树 记为Node。

curNode : 5 满足B 进行步骤1 最终打印5。

通过空闲指针遍历至6。

curNode : 6 满足A 空闲指针由5的右指针指向6 将该空闲指针取消掉 打印6。

通过6的右指针遍历到7。

curNode : 7 满足B 进行步骤1 最终打印7。

3. 步骤2最终移动到null结点 整个过程结束。

1) 二叉树的中序遍历

1. 初始化指针cur指向root

2. 当cur不为空时

  - 如果cur没有左子结点

      a) 打印出cur的值

    b) 将cur指针指向其右子节点

  - 反之

     将pre指针指向cur的左子树中的最右子节点 

     * 若pre不存在右子节点

          a) 将其右子节点指回cur

        b) cur指向其左子节点

     * 反之

      a) 将pre的右子节点置空

      b) 打印cur的值

      c) 将cur指针指向其右子节点

void middle_visit(TreeNode *root) {TreeNode*pre;TreeNode*cur;cur=root;while(cur){if(cur->left==NULL){std::cout<<cur->val<<std::endl;cur=cur->right;}else{pre=cur->left;while(pre->right!=NULL&&pre->right!=cur){pre=pre->right;}if(pre->right==NULL){pre->right=cur;cur=cur->left;}else{pre->right=NULL;std::cout<<cur->val<<std::endl;cur=cur->right;}}}
}

2)二叉树的前序遍历  前序遍历与中序遍历的差别只是打印的位置不同

1. 初始化指针cur指向root

2. 当cur不为空时

  - 如果cur没有左子结点

      a) 打印出cur的值

    b) 将cur指针指向其右子节点

  - 反之

     将pre指针指向cur的左子树中的最右子节点 

     * 若pre不存在右子节点

          a) 将其右子节点指回cur

                   b) 打印cur的值

        c) cur指向其左子节点

     * 反之

      a) 将pre的右子节点置空

      b) 将cur指针指向其右子节点

void pre_visit(TreeNode *root) {TreeNode*pre;TreeNode*cur;cur=root;while(cur){if(cur->left==NULL){std::cout<<cur->val<<std::endl;cur=cur->right;}else{pre=cur->left;while(pre->right!=NULL&&pre->right!=cur){pre=pre->right;}if(pre->right==NULL){pre->right=cur;std::cout<<cur->val<<std::endl;cur=cur->left;}else{pre->right=NULL;cur=cur->right;}}}
}

3)二叉树的后序遍历 也是打印的的方式不同

1. 初始化指针cur指向root

2. 当cur不为空时

  - 如果cur没有左子结点

      a) 打印出cur的值

    b) 将cur指针指向其右子节点

  - 反之

     将pre指针指向cur的左子树中的最右子节点 

     * 若pre不存在右子节点

          a) 将其右子节点指回cur

        b) cur指向其左子节点

     * 反之

      a) 将pre的右子节点置空

      b) 倒序输出从当前节点的左孩子到该前驱节点这条路径上的所有节点。

      c) 将cur指针指向其右子节点

 

void reverse(TreeNode*from,TreeNode*to){if(from==to)return;TreeNode *x=from;TreeNode*y=from->right;TreeNode*z;while(true){z=y->right;y->right=x;x=y;y=z;if(x==to)break;}
}void printReverse(TreeNode* from, TreeNode *to) // print the reversed tree nodes 'from' -> 'to'.
{reverse(from,to);TreeNode*p=to;while(true){printf("%d",p->val);if(p==from)break;p=p->right;}reverse(to,from);
}void post_visit(TreeNode *root) {TreeNode dump(0);dump.left = root;TreeNode *cur = &dump, *prev = NULL;while(cur) {if (cur->left == NULL) {cur = cur->right;} else {prev = cur->left;while (prev->right != NULL && prev->right != cur) {prev = prev->right;}if (prev->right == NULL) {prev->right = cur;cur = cur->left;} else {printReverse(cur->left, prev);prev->right = NULL;cur = cur->right;}}}
}

 

下面是本题方法二的代码,也是使用中序遍历找到两个节点 之后进行交换

void recoverTree(TreeNode *root) {TreeNode *first = NULL;//第一个逆序的节点TreeNode*second = NULL;//第二个逆序的节点TreeNode*parent = NULL;//中序遍历的前一个节点TreeNode *cur, *pre;cur = root;while(cur){if(cur->left==NULL){if(parent&&parent->val>cur->val){if(first==NULL)first=parent;second=cur;}parent=cur;cur=cur->right;}else{pre=cur->left;while(pre->right&&pre->right!=cur)pre=pre->right;if(pre->right==NULL){pre->right=cur;cur=cur->right;}else{pre->right=NULL;if(parent->val>cur->val){if(first==NULL)first=parent;second=cur;}parent=cur;cur=cur->right;}}}if (first && second) swap(first->val, second->val);
}

参考:http://www.cnblogs.com/AnnieKim/archive/2013/06/15/morristraversal.html

https://www.cnblogs.com/ariel-dreamland/p/9159781.html

 

这篇关于leetcode 99:恢复二叉搜索树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1130324

相关文章

使用Python实现网络设备配置备份与恢复

《使用Python实现网络设备配置备份与恢复》网络设备配置备份与恢复在网络安全管理中起着至关重要的作用,本文为大家介绍了如何通过Python实现网络设备配置备份与恢复,需要的可以参考下... 目录一、网络设备配置备份与恢复的概念与重要性二、网络设备配置备份与恢复的分类三、python网络设备配置备份与恢复实

MySQL使用binlog2sql工具实现在线恢复数据功能

《MySQL使用binlog2sql工具实现在线恢复数据功能》binlog2sql是大众点评开源的一款用于解析MySQLbinlog的工具,根据不同选项,可以得到原始SQL、回滚SQL等,下面我们就来... 目录背景目标步骤准备工作恢复数据结果验证结论背景生产数据库执行 SQL 脚本,一般会经过正规的审批

通过ibd文件恢复MySql数据的操作方法

《通过ibd文件恢复MySql数据的操作方法》文章介绍通过.ibd文件恢复MySQL数据的过程,包括知道表结构和不知道表结构两种情况,对于知道表结构的情况,可以直接将.ibd文件复制到新的数据库目录并... 目录第一种情况:知道表结构第二种情况:不知道表结构总结今天干了一件大事,安装1Panel导致原来服务

Python使用DeepSeek进行联网搜索功能详解

《Python使用DeepSeek进行联网搜索功能详解》Python作为一种非常流行的编程语言,结合DeepSeek这一高性能的深度学习工具包,可以方便地处理各种深度学习任务,本文将介绍一下如何使用P... 目录一、环境准备与依赖安装二、DeepSeek简介三、联网搜索与数据集准备四、实践示例:图像分类1.

MySQL InnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据

《MySQLInnoDB引擎ibdata文件损坏/删除后使用frm和ibd文件恢复数据》mysql的ibdata文件被误删、被恶意修改,没有从库和备份数据的情况下的数据恢复,不能保证数据库所有表数据... 参考:mysql Innodb表空间卸载、迁移、装载的使用方法注意!此方法只适用于innodb_fi

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespace id不一致处理

《mysql8.0无备份通过idb文件恢复数据的方法、idb文件修复和tablespaceid不一致处理》文章描述了公司服务器断电后数据库故障的过程,作者通过查看错误日志、重新初始化数据目录、恢复备... 周末突然接到一位一年多没联系的妹妹打来电话,“刘哥,快来救救我”,我脑海瞬间冒出妙瓦底,电信火苲马扁.

Git中恢复已删除分支的几种方法

《Git中恢复已删除分支的几种方法》:本文主要介绍在Git中恢复已删除分支的几种方法,包括查找提交记录、恢复分支、推送恢复的分支等步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录1. 恢复本地删除的分支场景方法2. 恢复远程删除的分支场景方法3. 恢复未推送的本地删除分支场景方法4. 恢复

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

C# ComboBox下拉框实现搜索方式

《C#ComboBox下拉框实现搜索方式》文章介绍了如何在加载窗口时实现一个功能,并在ComboBox下拉框中添加键盘事件以实现搜索功能,由于数据不方便公开,作者表示理解并希望得到大家的指教... 目录C# ComboBox下拉框实现搜索步骤一步骤二步骤三总结C# ComboBox下拉框实现搜索步骤一这