题目:给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

解法一:递归法+快慢双指针

和108题的区别在于,本题以链表形式给出树中所有节点元素,不能使用下标索引元素,只能使用指针访问链表中的中间元素。

本解法的技巧在于快、慢指针寻找中间节点

官解算法:

由于我们得到的是一个有序链表而不是数组,我们不能直接使用下标来访问元素。我们需要知道链表中的中间元素。
我们可以利用两个指针来访问链表中的中间元素。假设我们有两个指针 slow_ptr 和 fast_ptr。slow_ptr 每次向后移动一个节点而 fast_ptr 每次移动两个节点。当 fast_ptr 到链表的末尾时 slow_ptr 就访问到链表的中间元素。对于一个偶数长度的数组,中间两个元素都可用来作二叉搜索树的根。
当找到链表中的中间元素后,我们将链表从中间元素的左侧断开,做法是使用一个 prev_ptr 的指针记录 slow_ptr 之前的元素,也就是满足 prev_ptr.next = slow_ptr。断开左侧部分就是让 prev_ptr.next = None。
我们只需要将链表的头指针传递给转换函数,进行高度平衡二叉搜索树的转换。所以递归调用的时候,左半部分我们传递原始的头指针;右半部分传递 slow_ptr.next 作为头指针。

代码如下:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def sortedListToBST(self, head: ListNode) -> TreeNode:def rebuildTree(subhead):if not subhead:return Noneslow = subheadfast = subheadpre_next = ListNode(0)p = pre_nextwhile fast and fast.next:fast = fast.next.nextp.next = slowp = p.nextslow = slow.nextroot_val = slow.valroot = TreeNode(root_val)p.next = Noneroot.left = rebuildTree(pre_next.next)root.right = rebuildTree(slow.next)return rootreturn rebuildTree(head)执行结果:通过显示详情
执行用时 :152 ms, 在所有 python3 提交中击败了40.20%的用户
内存消耗 :16.1 MB, 在所有 python3 提交中击败了100.00%的用户

复杂度分析

  • 时间复杂度:O(N log N)
  • 空间复杂度:O(log N)

从执行结果上来看也很明显,内存消耗很小。只新增了一个节点pre_next。

解法二:递归法+转换成数组

和108题的区别在于,本题以链表形式给出树中所有节点元素。一种思路是遍历链表,将值存储成数组形式,然后利用108题的递归程序构建二叉树即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def sortedListToBST(self, head: ListNode) -> TreeNode:nums = []p = headwhile p:nums.append(p.val)p = p.nextdef rebuildTree(left, right):if left >= right:return Noneroot_idx = (left+right) // 2root_val = nums[root_idx]root = TreeNode(root_val)root.left = rebuildTree(left, root_idx)root.right = rebuildTree(root_idx + 1, right)return rootreturn rebuildTree(0, len(nums))执行结果:通过显示详情
执行用时 :128 ms, 在所有 python3 提交中击败了95.75%的用户
内存消耗 :19.1 MB, 在所有 python3 提交中击败了75.97%的用户

这个方法是空间换时间的经典案例:你可以通过使用更多空间来降低时间复杂度

在这个方法中,我们将给定的链表转成数组并利用数组来构建二叉搜索树。数组找中间元素只需要O(1)的时间,所以会降低整个算法的时间复杂度开销。

复杂度分析:

时间复杂度:时间复杂度降到了 O(N) ,因为需要将链表转成数组。而取中间元素的开销变成了 O(1) 所以整体的时间复杂度降低了。

空间复杂度:因为我们利用额外空间换取了时间复杂度的降低,空间复杂度变成了 O(N),相较于之前算法的 O(logN)​ 有所提升,因为创建数组的开销。

解法三:中序模拟遍历

前两种解法无法平衡 时间 和 空间复杂度,解法三是一种连全齐美的方法,同时拥有解法一的空间复杂度 和 解法二的时间复杂度。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def sortedListToBST(self, head: ListNode) -> TreeNode:size = 0p = headwhile p:size += 1p = p.nextdef rebuildTree(l, r):nonlocal headif l >= r:return Nonemid = (l+r)//2left = rebuildTree(l, mid)root = TreeNode(head.val)root.left = lefthead = head.nextroot.right = rebuildTree(mid+1, r)return rootreturn rebuildTree(0 ,size)执行结果:通过显示详情
执行用时 :132 ms, 在所有 python3 提交中击败了91.67%的用户
内存消耗 :20.5 MB, 在所有 python3 提交中击败了5.19%的用户

其实解法是我一直在思考的,如何由中序遍历序列构造二叉搜索树的问题??

这种构造方法,是由 bottom → top 的构造方法,前述的解法一 和 二 都是自顶向下的构造方法。可以手动推演递归的执行顺序,只有标记好每一层的递归创建的栈,方便回溯时确定左、右界限。

另外,官解中这个解法三给出的程序是有问题的。

使用双向链表构建二叉树_LeetCode-109 有序链表转换二叉搜索树相关推荐

  1. 109. 有序链表转换二叉搜索树

    链接:109. 有序链表转换二叉搜索树 题解:https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/so ...

  2. ( “树” 之 BST) 109. 有序链表转换二叉搜索树 ——【Leetcode每日一题】

    二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点. 二叉查找树中序遍历有序. 109. 有序链表转换二叉搜索树 给定一个单链表的头节点 head ,其中的元素 按升序排序 , ...

  3. 【LeetCode每日一题】——109.有序链表转换二叉搜索树

    文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[题目提示] 七[解题思路] 八[时间频度] 九[代码实现] 十[提交结果] 一[题目类别] 二叉树 二[题 ...

  4. Java实现 LeetCode 109 有序链表转换二叉搜索树

    109. 有序链表转换二叉搜索树 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. ...

  5. LeetCode 109. 有序链表转换二叉搜索树(快慢指针+递归)

    1. 题目 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 来源:力扣(LeetC ...

  6. Leetcode 109.有序链表转换二叉搜索树

    Time: 20190901 Type: Meidum 题目描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子 ...

  7. Leetcode 109. 有序链表转换二叉搜索树 解题思路及C++实现

    方法一:将链表转为数组来处理 解题思路: 因为链表不好处理,所以我先把链表处理成数组,因为是一个升序数组,所以直接将中间的数当成根结点,然后对左半部分的节点和右半部分的节点进行递归构建二叉搜索树. 在 ...

  8. LeetCode 109. 有序链表转换二叉搜索树

    思路: 快慢指针找到中间节点,中间节点为根节点, 将链表分为左右两部分(注意前半部分节点next置null),左部分为左子树,右部分为右子树 递归实现左右子树,返回根节点 public static ...

  9. 有序链表转换二叉搜索树

    109. 有序链表转换二叉搜索树 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. ...

  10. 【算法】有序链表转换二叉搜索树和从中序与后序遍历序列构造二叉树Java解答参考

    三道算法题 1.有序链表转换二叉搜索树 Java代码参考 2.从中序与后序遍历序列构造二叉树 Java代码参考 3.移除元素 Java代码参考 1.有序链表转换二叉搜索树 给定一个单链表,其中的元素按 ...

最新文章

  1. 代码和产品发布的几种方式
  2. tableau做rfm分析_RFM模型客户关系管理
  3. Windows下编译axel 2.6 / 2.11(下载神器)
  4. mysql数据库模型相应解释_数据库事务系列-MySQL跨行事务模型
  5. css3-5 css3鼠标、列表和尺寸样式怎么用(文字有关的样式会被继承)
  6. mipi协议_Cadence发布业界首款面向多协议PHY的验证IP产品
  7. Linux如何查看所有的用户和组信息
  8. 小白记事本--学不明白还怕忘记指针--loading未完待续
  9. 软件企业CMMI认证需要什么条件?
  10. 【渝粤题库】陕西师范大学200081中国古代文学(一)作业(高起本、高起专)
  11. 苹果计算机符号怎么打开,Mac电脑如何输入command(⌘)、option(⌥)、shift(⇧)等特殊符号...
  12. Qt实现在QLabel上显示图片并进行线条/矩形框/多边形的绘制
  13. 判别一个分解的无损连接性
  14. 怎么在线快速将多张CAD图纸转换成低版本DXF格式?
  15. 四级资料免费分享 【写作万能模板 + 听力高频词 + 核心500词 + 翻译必备句型 + 作文对策】 点个关注即可全部拿走!!!
  16. Tech Talk丨走进神奇的魔法世界之“魔法消除”技术
  17. 刷爆力扣之1 比特与 2 比特字符
  18. Unity -- 预制体与变体
  19. 谷歌翻译停服后,chrome无法自动翻译?解决办法来了~ (最新)
  20. php屏蔽蜘蛛,如何屏蔽垃圾蜘蛛抓取页面

热门文章

  1. 基于 libevent 开源框架实现的 web 服务器
  2. HTTP 304状态码
  3. 紫书 习题 8-2 UVa 1610 (暴力出奇迹)
  4. 残缺、时间一起的爱情
  5. some tools
  6. Android dex修复工具,Android 简单热修复(下)——基于DexClassLoader的实现
  7. node_modules/css-loader?{sourceMap:true}!./node_modules/vue-loader/lib/style-compiler?报错问提解决方案
  8. .net core判断当前访问源是PC端还是移动端
  9. PHP自定义数组转Json字符串函数
  10. Layer 提示框tips使用