一 目录
不折腾的前端,和咸鱼有什么区别
目录 |
---|
一 目录 |
二 前言 |
三 解题及测试 |
四 LeetCode Submit |
五 解题思路 |
二 前言
难度:简单
涉及知识:树
题目地址:https://leetcode-cn.com/problems/trim-a-binary-search-tree/
题目内容:
给定一个二叉搜索树,同时给定最小边界 L 和最大边界 R。
通过修剪二叉搜索树,使得所有节点的值在 [L, R] 中 (R>=L) 。
你可能需要改变树的根节点,
所以结果应当返回修剪好的二叉搜索树的新的根节点。
示例 1:
输入:
1
/ \
0 2
L = 1
R = 2
输出:
1
\
2
示例 2:
输入:
3
/ \
0 4
\
2
/
1
L = 1
R = 3
输出:
3
/
2
/
1
三 解题及测试
小伙伴可以先自己在本地尝试解题,再回来看看 jsliang 的解题思路。
LeetCode 给定函数体:
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {TreeNode} root
* @param {number} L
* @param {number} R
* @return {TreeNode}
*/
var trimBST = function(root, L, R) {
};
根据上面的已知函数,尝试破解本题吧~
确定了自己的答案再看下面代码哈~
index.js
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @name 修剪二叉搜索树
* @param {TreeNode} root
* @param {number} L
* @param {number} R
* @return {TreeNode}
*/
const trimBST = (root, L, R) => {
if (!root) {
return root;
}
if (root.val > R) {
return trimBST(root.left, L, R);
}
if (root.val < L) {
return trimBST(root.right, L, R);
}
root.left = trimBST(root.left, L, R);
root.right = trimBST(root.right, L, R);
return root;
};
const root = {
val: 1,
left: { val: 0, left: null, right: null },
right: { val: 2, left: null, right: null },
};
console.log(trimBST(root, 1, 2));
node index.js
返回:
{ val: 1,
left: null,
right: { val: 2, left: null, right: null } }
四 LeetCode Submit
执行结果:通过
执行用时:72 ms,在所有 JavaScript 提交中击败了 94.20% 的用户
内存消耗:39.3 MB,在所有 JavaScript 提交中击败了 29.41% 的用户
五 解题思路
看了一眼,不会,进入学习状态。
【题解区】 - 官方题解
const trimBST = (root, L, R) => {
if (!root) {
return root;
}
if (root.val > R) {
return trimBST(root.left, L, R);
}
if (root.val < L) {
return trimBST(root.right, L, R);
}
root.left = trimBST(root.left, L, R);
root.right = trimBST(root.right, L, R);
return root;
};
思路:
不知道你有没有听过一个词语,叫 “左右互搏”,这里要做个新定义了!
首先,我们知道,我们需要修剪树的范围在 [L, R]
区间,那么小于 L
或者大于 R
的,我们就需要抛弃。
然后,当我们判断一个树的节点为空 null
的时候,我们直接返回这个节点,告诉它走不下去了;当我们判断一个树的节点大于 R
的时候,就让它去遍历左子树;如果一个树的节点小于 L
的时候,就让它遍历右子树。
接着,如果这棵树是正常的,属于 [L, R]
区间的,那么我们就让它正常的遍历左子树或者右子树。
实例:
为了更方便我们了解机制,举个例子:
const root = {
val: 1,
left: { val: 0, left: null, right: null },
right: { val: 2, left: null, right: null },
};
const L = 1;
const R = 2;
我们在代码中进行 console.log
打印:
const trimBST = (root, L, R) => {
console.log(root);
if (!root) {
return root;
}
if (root.val > R) {
return trimBST(root.left, L, R);
}
if (root.val < L) {
return trimBST(root.right, L, R);
}
root.left = trimBST(root.left, L, R);
root.right = trimBST(root.right, L, R);
return root;
};
输出如下:
① { val: 1,
left: { val: 0, left: null, right: null },
right: { val: 2, left: null, right: null } }
② { val: 0, left: null, right: null }
③ null
④ { val: 2, left: null, right: null }
⑤ null
⑥ null
步骤:
一开始遍历的是整棵树,这点是毫无疑问的,然后节点
1
属于[1, 2]
区间内,所以正常遍历左右节点。遍历左节点
root.left = trimBST(root.left, L, R)
的时候,此时左子树的值val
为 0,符合root.val < L
,所以执行trimBST(root.right, L, R)
。此时树节点
{ val: 0, left: null, right: null }
的右节点为null
,所以返回的是null
。遍历右节点
root.right = trimBST(root.right, L, R)
的时候,此时右子树的值val
为 2,正常遍历左右节点。遍历节点为
2
的左子树,返回null
。遍历节点为
2
的右子树,返回null
。递归从步骤 1 到步骤 6 完毕,然后开始从步骤 6 开始向步骤 1 组装数据,最终返回我们需要的结果:
{ val: 1,
left: null,
right: { val: 2, left: null, right: null } }
Submit 提交:
执行结果:通过
执行用时:72 ms,在所有 JavaScript 提交中击败了 94.20% 的用户
内存消耗:39.3 MB,在所有 JavaScript 提交中击败了 29.41% 的用户
再次学到一个点,叫 “左右互搏”,它的作用是:
筛选一棵树中不需要的节点,并返回最终有效节点。
如果你还没看懂,建议可以尝试下理解下面两个例子:
例子 1
const root = {
val: 1,
left: {
val: 0,
left: null,
right: { val: 1.5, left: null, right: null },
},
right: { val: 2, left: null, right: null },
};
例子 2
const root = {
val: 3,
left: {
val: 0,
left: null,
right: {
val: 2,
left: { val: 1, left: null, right: null },
right: null,
},
},
right: { val: 4, left: null, right: null },
};
那么,本题就到此结束了。
如果你有更好的思路或者想法,欢迎评论留言或者私聊 jsliang~
不折腾的前端,和咸鱼有什么区别!
jsliang 会每天更新一道 LeetCode 题解,从而帮助小伙伴们夯实原生 JS 基础,了解与学习算法与数据结构。
浪子神剑 会每天更新面试题,以面试题为驱动来带动大家学习,坚持每天学习与思考,每天进步一点!
扫描上方二维码,关注 jsliang 的公众号(左)和 浪子神剑 的公众号(右),让我们一起折腾!
jsliang 的文档库 由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于https://github.com/LiangJunrong/document-library上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。