题目概述(中等难度)
描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
数据范围:输入二叉树的节点数0≤n≤1000,二叉树中每个节点的值 10000≤val≤1000
要求:空间复杂度O(1)(即在原树上操作),时间复杂度 O(n)
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出
输入描述:
二叉树的根节点
返回值描述
双向链表的其中一个头节点。
示例1:
输入: {10,6,14,4,8,12,16} 返回值: From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4; 说明: 输入题面图中二叉树,输出的时候将双向链表的头节点返回即可。
示例2
输入: {5,4,#,3,#,2,#,1} 返回值: From left to right are:1,2,3,4,5;From right to left are:5,4,3,2,1; 说明: 5 / 4 / 3 / 2 / 1 树的形状如上图
题目链接:
点我进入牛客网
思路与代码
思路展现
这道题目首秀按我们需要搞清楚两点:
1:第一点就是什么是二叉搜索树?
二叉搜索树(BST)满足的性质:
每个节点中的值必须大于(或等于)存储在其左子树中的任何值。
每个节点中的值必须小于(或等于)存储在其右子树中的任何值。
一个二叉搜索树的例子如下所示:
2:二叉搜索树经过中序遍历后便可以获取到排序的结果
搞懂了上面的两个点,我们的大概思路其实就已经有了:
首先我们使用中序遍历来获取相应的节点,因为中序遍历的结果是有序的,中序遍历可以拿到对应的节点,拿到对应的节点后我们就就可以改变left和right的指向,顺势将整个二叉树修改为双向链表.
转换为双向链表的时候我们的left和right不再代表左子树和右子树,而是代表双向链表中的前驱和后继.
代码示例
public class Solution { //prev用于记录每次节点的前驱,初始值为null public TreeNode prev = null; public void ConvertChild(TreeNode pCur) { if(pCur == null) { return; } ConvertChild(pCur.left); pCur.left = prev; if(prev != null) { prev.right = pCur; } prev = pCur; ConvertChild(pCur.right); } public TreeNode Convert(TreeNode pRootOfTree) { if(pRootOfTree == null) { return null; } ConvertChild(pRootOfTree); //定义我们要返回的当前双向链表的头节点 TreeNode head = pRootOfTree; while(head.left != null) { head = head.left; } return head; } }
整段代码的核心就在以下两个地方:
1:一个是对于如何将二叉树转换为双向链表的代码
2:一个是因为最开始我们输入的二叉树的根节点并不是现在我们所要的双向链表的头节点,所以当我们的二叉树转换为双向链表后,需要一直从原来二叉树根节点在双向链表中的位置处开始向前遍历,直到找到我们双向链表的头节点,
时间复杂度 : O(n),其中 n 为二叉树的节点个数。在递归调用的时候二叉树的每个节点最多被访问一次,因此时间复杂度为 O(n)。
空间复杂度 : O(n),其中 n 为二叉树的节点个数。递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,即二叉树的高度。最坏情况下二叉树为一条链,树的高度为 n ,递归最深达到 n 层,故最坏情况下空间复杂度为 O(n).
总结
这道题目是非常经典的一道题目,题目来源于剑指offer原题,希望大家后面可以多把这道题目刷刷.