Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers as synonymous to the previous and next pointers in a doubly-linked list.

Let's take the following BST as an example, it may help you understand the problem better:

We want to transform this BST into a circular doubly linked list. Each node in a doubly linked list has a predecessor and successor. For a circular doubly linked list, the predecessor of the first element is the last element, and the successor of the last element is the first element.

The figure below shows the circular doubly linked list for the BST above. The "head" symbol means the node it points to is the smallest element of the linked list.

Specifically, we want to do the transformation in place. After the transformation, the left pointer of the tree node should point to its predecessor, and the right pointer should point to its successor. We should return the pointer to the first element of the linked list.

The figure below shows the transformed BST. The solid line indicates the successor relationship, while the dashed line means the predecessor relationship.

这道题给了一个二叉搜索树,让我们将其转化为双向链表。并且题目中给了一个带图的例子,帮助理解。题目本身并不难理解,仔细观察下给的示例图。首先,转化成双向链表的每个结点都有 left 和 right 指针指向左右两个结点,不管其原来是否是叶结点还是根结点,转换后统统没有区别。其次,这是个循环双向链表,即首尾结点是相连的,原先的二叉搜索树中的最左结点和最右结点,现在也互相连接起来了。最后,返回的结点不再是原二叉搜索树的根结点 root 了,而是最左结点,即最小值结点。

好,发现了上述规律后,来考虑如何破题。根据博主多年经验,跟二叉搜索树有关的题,肯定要利用其性质,即左<根<右,即左子结点值小于根结点值小于右子结点值。而且十有八九都得用中序遍历来解,因为中序遍历的顺序就是左根右啊,跟性质吻合。观察到原二叉搜索树中结点4连接着结点2和结点5,而在双向链表中,连接的是结点3和结点5,这就是为啥要用中序遍历了,因为只有中序遍历,结点3之后才会遍历到结点4,这时候可以将结点3和结点4串起来。决定了用中序遍历之后,就要考虑是迭代还是递归的写法,博主建议写递归的,一般写起来都比较简洁,而且递归是解树类问题的神器啊,十有八九都是用递归,一定要熟练掌握。再写中序遍历之前,其实还有难点,因为需要把相邻的结点连接起来,所以需要知道上一个遍历到的结点是什么,所以用一个变量 pre,来记录上一个遍历到的结点。还需要一个变量 head,来记录最左结点,这样的话,在递归函数中,先判空,之后对左子结点调用递归,这样会先一直递归到最左结点,此时如果 head 为空的话,说明当前就是最左结点,赋值给 head 和 pre,对于之后的遍历到的结点,那么可以和 pre 相互连接上,然后 pre 赋值为当前结点 node,再对右子结点调用递归即可,参见代码如下:

解法一:

class Solution {
public:
Node* treeToDoublyList(Node* root) {
if (!root) return NULL;
Node *head = NULL, *pre = NULL;
inorder(root, pre, head);
pre->right = head;
head->left = pre;
return head;
}
void inorder(Node* node, Node*& pre, Node*& head) {
if (!node) return;
inorder(node->left, pre, head);
if (!head) {
head = node;
pre = node;
} else {
pre->right = node;
node->left = pre;
pre = node;
}
inorder(node->right, pre, head);
}
};

虽然说树类问题首推递归解法,但是中序遍历是可以用迭代来写的,可以参见博主之前的博客 Binary Tree Inorder Traversal。迭代写法借用了栈,其实整体思路和递归解法没有太大的区别,递归的本质也是将断点存入栈中,以便之后可以返回,这里就不多讲解了,可以参见上面的讲解,参见代码如下:

解法二:

class Solution {
public:
Node* treeToDoublyList(Node* root) {
if (!root) return NULL;
Node *head = NULL, *pre = NULL;
stack<Node*> st;
while (root || !st.empty()) {
while (root) {
st.push(root);
root = root->left;
}
root = st.top(); st.pop();
if (!head) head = root;
if (pre) {
pre->right = root;
root->left = pre;
}
pre = root;
root = root->right;
}
head->left = pre;
pre->right = head;
return head;
}
};

这道题还有一种使用分治法 Divide and Conquer 来做的方法。分治法,顾名思义,就是把一项任务分成两半,用相同的逻辑去分别处理,之后再粘合起来。混合排序 Merge Sort 用的也是这种思路。这里可以对左右子结点调用递归函数,suppose 我们得到了两个各自循环的有序双向链表,然后把根结点跟左右子结点断开,将其左右指针均指向自己,这样就形成了一个单个结点的有序双向链表,虽然只是个光杆司令,但人家仍然是有序双向链表,不是沙雕,就问你叼不叼。那么此时只要再写一个连接两个有序双向链表的子函数,就可以将这三个有序双向链表按顺序链接起来了。

而链接两个有序双向链表的子函数也简单,首先判空,若一个为空,则返回另一个。如果两个都不为空,则把第一个链表的尾结点的右指针链上第二个链表的首结点,同时第二个链表的首结点的左指针链上第一个链表的尾结点。同理,把第二个链表的尾结点的右指针链上第一个链表的首结点,同时第一个链表的首结点的左指针链上第二个链表的尾结点。有木有读晕,可以自己画图,其实很好理解的诶,参见代码如下:

解法三:

class Solution {
public:
Node* treeToDoublyList(Node* root) {
if (!root) return NULL;
Node *leftHead = treeToDoublyList(root->left);
Node *rightHead = treeToDoublyList(root->right);
root->left = root;
root->right = root;
return connect(connect(leftHead, root), rightHead);
}
Node* connect(Node* node1, Node* node2) {
if (!node1) return node2;
if (!node2) return node1;
Node *tail1 = node1->left, *tail2 = node2->left;
tail1->right = node2;
node2->left = tail1;
tail2->right = node1;
node1->left = tail2;
return node1;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/426

类似题目:

Binary Tree Inorder Traversal

参考资料:

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/discuss/174111/inorder-vs-divide-and-conquer

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/discuss/151228/Java-Simple-InOrder-no-Global

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/discuss/138621/C%2B%2B-solution

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/discuss/149151/Concise-Java-solution-Beats-100

https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/discuss/154659/Divide-and-Conquer-without-Dummy-Node-Java-Solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Convert Binary Search Tree to Sorted Doubly Linked List 将二叉搜索树转为有序双向链表的更多相关文章

  1. LeetCode 426. Convert Binary Search Tree to Sorted Doubly Linked List

    原题链接在这里:https://leetcode.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/ 题目: C ...

  2. 【LeetCode】426. Convert Binary Search Tree to Sorted Doubly Linked List 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 迭代 日期 题目地址:https://leetc ...

  3. [leetcode]426. Convert Binary Search Tree to Sorted Doubly Linked List二叉搜索树转有序双向链表

    Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers ...

  4. 426. Convert Binary Search Tree to Sorted Doubly Linked List把bst变成双向链表

    [抄题]: Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right po ...

  5. LeetCode426.Convert Binary Search Tree to Sorted Doubly Linked List

    题目 Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right point ...

  6. [LC] 426. Convert Binary Search Tree to Sorted Doubly Linked List

    Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers ...

  7. PAT 1043 Is It a Binary Search Tree (25分) 由前序遍历得到二叉搜索树的后序遍历

    题目 A Binary Search Tree (BST) is recursively defined as a binary tree which has the following proper ...

  8. 第33题:LeetCode255 Verify Preorder Sequence in Binary Search Tree 验证先序遍历是否符合二叉搜索树

    题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 考点 1.BST 二叉搜索树 2.递归 思路 1.后序 ...

  9. LeetCode: Validata Binary Search Tree

    LeetCode: Validata Binary Search Tree Given a binary tree, determine if it is a valid binary search ...

随机推荐

  1. Exponent CMS 2.3.9 配置文件写入 Getshell分析

    在 install/index.php 的第44行 expString::sanitize($_REQUEST); 跟进sanitize函数 public static function saniti ...

  2. [译]Ocelot - Middleware Injection and Overrides

    原文 使用这个特性的时候要小心点. 可以如下一样提供一些中间件用以覆盖默认的中间件: var configuration = new OcelotPipelineConfiguration { Pre ...

  3. mvc 在弹出框中实现文件下载

    var myParent = parent.parent.parent.parent.parent.parent.parent.parent.parent.parent.parent.parent; ...

  4. 命令框下上传到gitee

    git常用命令 C:\Users\Administrator>cd www/p2p设置账号C:\Users\Administrator\www\p2p>git config --globa ...

  5. AUTOCAD参数约束功能

    概要:http://through-the-interface.typepad.com/through_the_interface/2011/08/a-simplified-net-api-for-a ...

  6. PGCD2 - Primes in GCD Table (Hard)

    这题肝了三四天,其他啥也没做... 传送门 然后...双倍经验 简单版 不知道为什么会脑抽去帮 LZ_101 大佬验题... 题目和被 A 穿的 PGCD 一样,数据范围变成大概 2e11 ... 于 ...

  7. centos7.6环境下编译安装tengine-2.2.2的编译安装

    centos7.6环境下编译安装tengine-2.2.2的编译安装 .获取tengine2..2的源码包 http://tengine.taobao.org/download/tengine-2.2 ...

  8. 帆软报表(finereport)单元格中各颜色标识的含义

    帆软报表(finereport)单元格中,可根据单元格角标的颜色判断单元格进行的操作 过滤:单元格左下角黄色三角形 条件属性:单元格左上角红色三角形.  控件:单元格右侧中间的各种矩形.  左父格:单 ...

  9. 【原创】运维基础之Zabbix(1)简介、安装、使用

    zabbix 4 官方:https://www.zabbix.com/ 一 简介 Monitor anythingSolutions for any kind of IT infrastructure ...

  10. 解决前后端分离后的Cookie跨域问题

    一. 前端Ajax关键配置 $.ajax({ type: "post", url: xxx, data: xxx, contentType: 'application/json', ...