使用双向链表构建二叉树_LeetCode-109 有序链表转换二叉搜索树
题目:给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 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 有序链表转换二叉搜索树相关推荐
- 109. 有序链表转换二叉搜索树
链接:109. 有序链表转换二叉搜索树 题解:https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/so ...
- ( “树” 之 BST) 109. 有序链表转换二叉搜索树 ——【Leetcode每日一题】
二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点. 二叉查找树中序遍历有序. 109. 有序链表转换二叉搜索树 给定一个单链表的头节点 head ,其中的元素 按升序排序 , ...
- 【LeetCode每日一题】——109.有序链表转换二叉搜索树
文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[题目提示] 七[解题思路] 八[时间频度] 九[代码实现] 十[提交结果] 一[题目类别] 二叉树 二[题 ...
- Java实现 LeetCode 109 有序链表转换二叉搜索树
109. 有序链表转换二叉搜索树 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. ...
- LeetCode 109. 有序链表转换二叉搜索树(快慢指针+递归)
1. 题目 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 来源:力扣(LeetC ...
- Leetcode 109.有序链表转换二叉搜索树
Time: 20190901 Type: Meidum 题目描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子 ...
- Leetcode 109. 有序链表转换二叉搜索树 解题思路及C++实现
方法一:将链表转为数组来处理 解题思路: 因为链表不好处理,所以我先把链表处理成数组,因为是一个升序数组,所以直接将中间的数当成根结点,然后对左半部分的节点和右半部分的节点进行递归构建二叉搜索树. 在 ...
- LeetCode 109. 有序链表转换二叉搜索树
思路: 快慢指针找到中间节点,中间节点为根节点, 将链表分为左右两部分(注意前半部分节点next置null),左部分为左子树,右部分为右子树 递归实现左右子树,返回根节点 public static ...
- 有序链表转换二叉搜索树
109. 有序链表转换二叉搜索树 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. ...
- 【算法】有序链表转换二叉搜索树和从中序与后序遍历序列构造二叉树Java解答参考
三道算法题 1.有序链表转换二叉搜索树 Java代码参考 2.从中序与后序遍历序列构造二叉树 Java代码参考 3.移除元素 Java代码参考 1.有序链表转换二叉搜索树 给定一个单链表,其中的元素按 ...
最新文章
- 代码和产品发布的几种方式
- tableau做rfm分析_RFM模型客户关系管理
- Windows下编译axel 2.6 / 2.11(下载神器)
- mysql数据库模型相应解释_数据库事务系列-MySQL跨行事务模型
- css3-5 css3鼠标、列表和尺寸样式怎么用(文字有关的样式会被继承)
- mipi协议_Cadence发布业界首款面向多协议PHY的验证IP产品
- Linux如何查看所有的用户和组信息
- 小白记事本--学不明白还怕忘记指针--loading未完待续
- 软件企业CMMI认证需要什么条件?
- 【渝粤题库】陕西师范大学200081中国古代文学(一)作业(高起本、高起专)
- 苹果计算机符号怎么打开,Mac电脑如何输入command(⌘)、option(⌥)、shift(⇧)等特殊符号...
- Qt实现在QLabel上显示图片并进行线条/矩形框/多边形的绘制
- 判别一个分解的无损连接性
- 怎么在线快速将多张CAD图纸转换成低版本DXF格式?
- 四级资料免费分享 【写作万能模板 + 听力高频词 + 核心500词 + 翻译必备句型 + 作文对策】 点个关注即可全部拿走!!!
- Tech Talk丨走进神奇的魔法世界之“魔法消除”技术
- 刷爆力扣之1 比特与 2 比特字符
- Unity -- 预制体与变体
- 谷歌翻译停服后,chrome无法自动翻译?解决办法来了~ (最新)
- php屏蔽蜘蛛,如何屏蔽垃圾蜘蛛抓取页面
热门文章
- 基于 libevent 开源框架实现的 web 服务器
- HTTP 304状态码
- 紫书 习题 8-2 UVa 1610 (暴力出奇迹)
- 残缺、时间一起的爱情
- some tools
- Android dex修复工具,Android 简单热修复(下)——基于DexClassLoader的实现
- node_modules/css-loader?{sourceMap:true}!./node_modules/vue-loader/lib/style-compiler?报错问提解决方案
- .net core判断当前访问源是PC端还是移动端
- PHP自定义数组转Json字符串函数
- Layer 提示框tips使用