刷题使我快乐,满脸开心.jpg
- 来源:力扣(LeetCode)
- 链接:https://leetcode.cn/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/
- 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目
将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 。
对于双向循环列表,你可以将左右孩子指针作为双向循环链表的前驱和后继指针,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
特别地,我们希望可以 就地 完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中最小元素的指针。
示例 1:
输入:root = [4,2,5,1,3]
输出:[1,2,3,4,5]
解释:下图显示了转化后的二叉搜索树,实线表示后继关系,虚线表示前驱关系。
示例 2:
输入:root = [2,1,3]
输出:[1,2,3]
示例 3:
输入:root = []
输出:[]
解释:输入是空树,所以输出也是空链表。
示例 4:
输入:root = [1]
输出:[1]
提示:
-1000 <= Node.val <= 1000
Node.left.val < Node.val < Node.right.val
Node.val
的所有值都是独一无二的0 <= Number of Nodes <= 2000
思路
这个题目还是挺有意思的,关键点有几个
- 二叉搜索树的概念及其遍历方式
- 因需要
原地生成
,所以在生成排序链表的同时,要不影响后续节点的加入
第二点往往会被忽略,因为选择了dfs
的话,下意识从最深处节点开始(也就是排序后的最小值)一个个链接,此时正好符合了第二点的要求。
二叉搜索树特点:
- 左子树所有节点均小于根节点
- 右子树所有节点均大于根节点
所以在此情况下解法就出来了:
DFS
前序遍历,遍历节点- 使用头尾双指针方法,将一个个节点拼接起来,最终再拼接头尾即可
至此,上代码
代码
class Solution {
public:
Node* treeToDoublyList(Node* root) {
if(root == nullptr) return nullptr;
dfs(root);
// 拼接头尾
head->left = tail;
tail->right = head;
return head;
}
private:
Node *tail, *head;
void dfs(Node* now) {
if(now == nullptr) return;
dfs(now->left);
// 开始时确定头结点,使用尾结点作为缓存指针拼接后续节点
if(tail != nullptr) tail->right = now;
else head = now;
now->left = tail;
// 移动尾部指针,等待拼接下一个
tail = now;
dfs(now->right);
}
};