LeetCode897 递增顺序搜索树 & 剑指OfferII 052 展平二叉搜索树

LeetCode897 递增顺序搜索树 & 剑指OfferII 052 展平二叉搜索树

题目

在这里插入图片描述
在这里插入图片描述

解题

二叉搜索树的增序排列就是中序遍历的顺序。

LeetCode426 将二叉搜索树转化为排序的双向链表 & 剑指Offer 36 二叉搜索树与双向链表 的简单版,426 题需要构造的 双向循环链表,本题是单向链表,相当于 left 不用指向前驱节点,直接指向 null 就行,而且最后首尾相连的一步也不用。

具体的思路不重复了,直接指路 426 题,一些注意点都标明出来啦!

其实有好几道将二叉树转换为链表的题目,本质上是中序/前序/后序遍历。

  1. 可以将节点按顺序放入一个数组中,最后去修改 left 和 right 指针
  2. 也可以原地修改,但是 要特别注意的是 left 指针和 right 指针什么时候可以修改:比如前序遍历的递归写法,如果在处理 root 的左子树根节点时,把 root.right 指向左子树,那么右子树的记录便丢掉了(LeetCode114 二叉树展开为链表)。再例如本题:因为在处理 root 根节点时,左子树已经处理完毕,left 指针可以置为 null,但倘若 visit 函数写成下面这样,就会出现环:
// javascript
const visit = (cur) => {
	if (head === null) {
    	head = cur;
 	}
    if (tail !== null) {
    	tail.left = null;  // 等到下一个节点加入时才来改变 tail 的 left
		tail.right = cur;
    }
	tail = cur;
};
[2,1,4,null,null,3]
最后一个节点是节点4,节点4后面没有节点加入,所以它的left指针没有机会被置为null
所以节点4的left指针一直指向节点3。而节点3的后继节点是节点4,节点3的right指向节点4
于是就有了环

因为不同的解题思路的处理流程不一样,所以也不能一概而论地讲出一个结论来,还是要拿着图分析一遍再来敲代码,敲完代码后再拿着图去检验一下。

在 visit 的函数里有判断 head 和 tail 是否为 null 的语句,官方用了链表常用的方法:设置了哑节点,可以省去对边界情况的讨论。

解题一:递归

// javascript
var increasingBST = function(root) {
    const dfs = (root) => {
        if (root === null) return;
        dfs(root.left);
        visit(root);
        dfs(root.right);
    };
    const visit = (cur) => {
        if (head === null) {
            head = cur;
        }
        if (tail !== null) {
            tail.right = cur;
            cur.left = null;
        }
        tail = cur;
    };
    let head = null, tail = null;
    dfs(root);
    return head;
};

解题二:栈

// javascript
var increasingBST = function(root) {
    const visit = (cur) => {
        if (head === null) {
            head = cur;
        }
        if (tail !== null) {
            tail.right = cur;
            cur.left = null;
        }
        tail = cur;
    };
    let head = null, tail = null;
    const stk = new Array();
    while (root !== null || stk.length > 0) {
        while (root !== null) {
            stk.push(root);
            root = root.left;
        }
        root = stk.pop();
        visit(root);
        root = root.right;
    }
    return head;
};

解题三:Morris 中序遍历

// javascript
var increasingBST = function(root) {
    const visit = (cur) => {
        if (head === null) {
            head = cur;
        }
        if (tail !== null) {
            tail.right = cur;
            cur.left = null;
        }
        tail = cur;
    };
    let head = null, tail = null;
    while (root !== null) {
        if (root.left !== null) {
            let predecessor = root.left;
            while (predecessor.right !== null && predecessor.right !== root) {
                predecessor = predecessor.right;
            }
            if (predecessor.right === null) {
                predecessor.right = root;
                root = root.left;
            } else if (predecessor.right === root) {
            	// 再次强调一下顺序丫!
                predecessor.right = null;
                visit(root);
                root = root.right;
            }
        } else {
            visit(root);
            root = root.right;
        }
    }
    return head;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值