潍坊网站收录,网站建设书生商友,萧山网站制作公司,申请网址的网站669. 修剪二叉搜索树
思路
递归法
从图中可以看出需要重构二叉树#xff0c;想想是不是本题就有点复杂了。
其实不用重构那么复杂。
在上图中我们发现节点0并不符合区间要求#xff0c;那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了#xff08;就是把节点…669. 修剪二叉搜索树
思路
递归法
从图中可以看出需要重构二叉树想想是不是本题就有点复杂了。
其实不用重构那么复杂。
在上图中我们发现节点0并不符合区间要求那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了就是把节点0从二叉树中移除如图 理解了最关键部分了我们再递归三部曲
确定递归函数的参数以及返回值
这里我们为什么需要返回值呢
因为是要遍历整棵树做修改其实不需要返回值也可以我们也可以完成修剪其实就是从二叉树中移除节点的操作。
但是有返回值更方便可以通过递归函数的返回值来移除节点。
这样的做法在二叉树搜索树中的插入操作 (opens new window)和二叉树搜索树中的删除操作 (opens new window)中大家已经了解过了。
代码如下
TreeNode trimNode(TreeNode cur, int low, int high)确定终止条件
修剪的操作并不是在终止条件上进行的所以就是遇到空节点返回就可以了。
if (cur null){return null;
}
确定单层递归的逻辑
如果root当前节点的元素小于low的数值那么应该递归右子树并返回右子树符合条件的头结点。
代码如下
// 寻找符合区间[low, high]的节点
if (cur.val low){TreeNode right trimNode(cur.right, low, high);return right;
}
如果root(当前节点)的元素大于high的那么应该递归左子树并返回左子树符合条件的头结点。
代码如下
if (cur.val high){TreeNode left trimNode(cur.left,low,high);return left;
}
接下来要将下一层处理完左子树的结果赋给root-left处理完右子树的结果赋给root-right。
最后返回root节点代码如下
cur.left trimNode(cur.left,low,high);//cur.left接入符合条件的左孩子
cur.right trimNode(cur.right,low,high);//cur.right接入符合条件的右孩子
return cur;
此时大家是不是还没发现这多余的节点究竟是如何从二叉树中移除的呢
在回顾一下上面的代码针对下图中二叉树的情况 如下代码相当于把节点0的右孩子节点2返回给上一层
// 寻找符合区间[low, high]的节点
if (cur.val low){TreeNode right trimNode(cur.right, low, high);return right;
}然后如下代码相当于用节点3的左孩子 把下一层返回的 节点0的右孩子节点2 接住。
cur.left trimNode(cur.left,low,high);//cur.left接入符合条件的左孩子
此时节点3的左孩子就变成了节点2将节点0从二叉树中移除了。
整体代码如下
class Solution {public TreeNode trimBST(TreeNode root, int low, int high) {return trimNode(root,low,high);}TreeNode trimNode(TreeNode cur, int low, int high){if (cur null){return null;}// 寻找符合区间[low, high]的节点if (cur.val low){TreeNode right trimNode(cur.right, low, high);return right;}if (cur.val high){TreeNode left trimNode(cur.left,low,high);return left;}cur.left trimNode(cur.left,low,high);//cur.left接入符合条件的左孩子cur.right trimNode(cur.right,low,high);//cur.right接入符合条件的右孩子return cur;}
} 108.将有序数组转换为二叉搜索树
思路
题目中说要转换为一棵高度平衡二叉搜索树。为什么强调要平衡呢
因为只要给我们一个有序数组如果强调平衡都可以以线性结构来构造二叉搜索树。
例如 有序数组[-10-3059] 就可以构造成这样的二叉搜索树如图。 上图中是符合二叉搜索树的特性吧如果要这么做的话是不是本题意义就不大了所以才强调是平衡二叉搜索树。
其实数组构造二叉树构成平衡树是自然而然的事情因为大家默认都是从数组中间位置取值作为节点元素一般不会随机取。所以想构成不平衡的二叉树是自找麻烦。
本质就是寻找分割点分割点作为当前节点然后递归左区间和右区间。
分割点就是数组中间位置的节点。
那么为问题来了如果数组长度为偶数中间节点有两个取哪一个
取哪一个都可以只不过构成了不同的平衡二叉搜索树。
例如输入[-10,-3,0,5,9]
如下两棵树都是这个数组的平衡二叉搜索树 如果要分割的数组长度为偶数的时候中间元素为两个是取左边元素 就是树1取右边元素就是树2。
递归
递归三部曲
确定递归函数返回值及其参数
删除二叉树节点增加二叉树节点都是用递归函数的返回值来完成这样是比较方便的。
相信大家如果仔细看了二叉树搜索树中的插入操作 (opens new window)和二叉树搜索树中的删除操作 (opens new window)一定会对递归函数返回值的作用深有感触。
那么本题要构造二叉树依然用递归函数的返回值来构造中节点的左右孩子。
再来看参数首先是传入数组然后就是左下标left和右下标right我们在二叉树构造二叉树登场 (opens new window)中提过在构造二叉树的时候尽量不要重新定义左右区间数组而是用下标来操作原数组。
所以代码如下
// 左闭右闭区间[left, right]
TreeNode sortTree(int[] nums,int left,int right)这里注意我这里定义的是左闭右闭区间在不断分割的过程中也会坚持左闭右闭的区间这又涉及到我们讲过的循环不变量。
确定递归终止条件
这里定义的是左闭右闭的区间所以当区间 left right的时候就是空节点了。
代码如下
if (left right){return null;}确定单层递归的逻辑
首先取数组中间元素的位置不难写出int mid (left right) / 2;这么写其实有一个问题就是数值越界例如left和right都是最大int这么操作就越界了在二分法 (opens new window)中尤其需要注意
所以可以这么写int mid left ((right - left) / 2);
但本题leetcode的测试数据并不会越界所以怎么写都可以。但需要有这个意识
取了中间位置就开始以中间位置的元素构造节点代码TreeNode cur new TreeNode(nums[mid]); 。
接着划分区间root的左孩子接住下一层左区间的构造节点右孩子接住下一层右区间构造的节点。
最后返回root节点单层递归整体代码如下
int mid (leftright) /2;
TreeNode cur new TreeNode(nums[mid]);
cur.left sortTree(nums,left,mid-1);
cur.right sortTree(nums,mid1,right);
return cur;
递归整体代码如下
class Solution {public TreeNode sortedArrayToBST(int[] nums) {return sortTree(nums,0, nums.length-1);}// 左闭右闭区间[left, right]TreeNode sortTree(int[] nums,int left,int right){if (left right){return null;}int mid (leftright) /2;TreeNode cur new TreeNode(nums[mid]);cur.left sortTree(nums,left,mid-1);cur.right sortTree(nums,mid1,right);return cur;}
} 538.把二叉搜索树转换为累加树
思路
如何累加遇到一个节点然后再遍历其他节点累加
然后再发现这是一棵二叉搜索树二叉搜索树啊这是有序的啊。
那么有序的元素如何求累加呢
其实这就是一棵树大家可能看起来有点别扭换一个角度来看这就是一个有序数组[2, 5, 13]求从后到前的累加数组也就是[20, 18, 13]是不是感觉这就简单了。
为什么变成数组就是感觉简单了呢
因为数组大家都知道怎么遍历啊从后向前挨个累加就完事了这换成了二叉搜索树看起来就别扭了一些是不是。
那么知道如何遍历这个二叉树也就迎刃而解了从树中可以看出累加的顺序是右中左所以我们需要反中序遍历这个二叉树然后顺序累加就可以了。
#递归
遍历顺序如图所示 本题依然需要一个pre指针记录当前遍历节点cur的前一个节点这样才方便做累加。
pre指针的使用技巧在二叉树搜索树的最小绝对差 (opens new window)和二叉树我的众数是多少 (opens new window)都提到了这是常用的操作手段。
递归函数参数以及返回值
这里很明确了不需要递归函数的返回值做什么操作了要遍历整棵树。
同时需要定义一个全局变量pre用来保存cur节点的前一个节点的数值。
代码如下
// 记录前一个节点的数值
TreeNode pre new TreeNode(0);
确定终止条件
遇空就终止。
if (node null){return null;
}
确定单层递归的逻辑
注意要右中左来遍历二叉树 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。
代码如下
//右
sumTree(node.right);
//中
node.val node.val pre.val;
pre node;
//左
sumTree(node.left);return node;递归法整体代码如下
class Solution {public TreeNode convertBST(TreeNode root) {return sumTree(root);}// 记录前一个节点的数值TreeNode pre new TreeNode(0);//右中左TreeNode sumTree(TreeNode node){if (node null){return null;}//右sumTree(node.right);//中node.val node.val pre.val;pre node;//左sumTree(node.left);return node;}
} 以上为我做题时候的相关思路自己的语言组织能力较弱很多都是直接抄卡哥的有错误望指正。