文章:代码随想录
修剪二叉搜索树:
思路:
这里主要知道两点:
超出下界,删除这个节点的这节点的左子树,上界则是这个节点和这个节点的右子树.
所以直接返回这个节点的另一颗树,就可以删除。
还有一点就是删除节点的右子树或者左子树可能还会存在超出界限的节点,所以超出下界的节点还得往右子树递归,上界则往左子树.这里迭代法比较难思考出来,因为从上往下不是找被删除的界限节点,而是找到符合要求的根节点,从根节点往下修剪。
代码:
//递归法
public static TreeNode trimBST(TreeNode root, int low, int high) {
if(root == null) return null;
//如果当前节点小于最小边界,往右子树找看是否还有不在范围内的节点
if(root.val<low) return trimBST(root.right,low,high);
//如果当前节点大于最大边界,往左子树找看是否还有不在范围内的节点
if(root.val>high) return trimBST(root.left,low,high);
//在区域范围内,往左右子树递归看看有没有超出边界的。
root.left=trimBST(root.left,low,high);
root.right=trimBST(root.right,low,high);
//往上一层返回自己
//如果不符合要求不会走到这里,会在上面请求往下递归,最后返回给上层符合条件的节点。
return root;
}
//迭代法
//这里迭代我们找的是符合条件的节点,从符合条件的节点往下遍历,而不是找到不符合条件的节点往上返回.
//因为这是迭代不是递归,无法将符合条件的节点返回给上一层,只能从上一层来往下修剪不符合条件的节点。
public static TreeNode trimBST2(TreeNode root, int low, int high) {
if(root == null) return null;
//找到当前树符合区间的节点
//也就是先定位合法的root。
while (root!=null && (root.val<low || root.val>high)){
//比下界低则往右找
if(root.val<low){
root=root.right;
}else {
//比上界高则往左找
root=root.left;
}
}
//证明整棵树都需要被修剪
if (root==null) return root;
//到这步说明root是符合条件的节点,开始往下修剪
//root始终得指向合法根节点的位置
//往左修剪
for (TreeNode node=root; node.left != null;){
if (node.left.val<low){
//修剪,修剪掉不符合条件的节点和它的左子树
node.left=node.left.right;
}else node=node.left;
}
//往右修剪
for (TreeNode node=root; node.right != null;){
if (node.right.val>high){
//修剪,修剪掉不符合条件的节点和它的右子树
node.right=node.right.left;
}else node=node.right;
}
return root;
}
将有序数组转换为二叉搜索树:
思路:
其实就是二分法.递归找到中间索引作为中节点,然后左子树则是中间索引的左边,右子树则是中间节点的右边。
/要求每个节点都是高度平衡搜索树,也就是对每个节点都要取中间,然后王左右两边构建子树,那么递归很容易就写出来
//二分法。
public class SortedArrayToBST {
public TreeNode sortedArrayToBST(int[] nums) {
if (nums.length == 0) return null;
//左闭右闭
return getTree(nums, 0, nums.length - 1);
}
private TreeNode getTree(int[] nums, int left, int right) {
if (right < left) return null;
//防止溢出
int midIndex = left + (right - left) / 2;
TreeNode node = new TreeNode(nums[midIndex]);
node.left = getTree(nums, left, midIndex - 1);
node.right = getTree(nums, midIndex + 1, right);
return node;
}
//迭代版
public TreeNode sortedArrayToBST2(int[] nums) {
if (nums.length == 0) return null;
//左闭右闭
//初始根节点
TreeNode root = new TreeNode(nums[0]);
Queue<TreeNode> nodeQueue = new LinkedList<>();
nodeQueue.offer(root);
Queue<Integer> leftQueue = new LinkedList<>();
leftQueue.offer(0);
Queue<Integer> rightQueue = new LinkedList<>();
rightQueue.offer(nums.length - 1);
while (!nodeQueue.isEmpty()) {
//改变当前节点的值,所以只需要左右两个参数,如果是构建下一层节点的左右子树并且赋值,那就需要左右子节点的left和right,也就是四个参数
TreeNode top = nodeQueue.poll();
int left = leftQueue.poll();
int right = rightQueue.poll();
int mid = left + (right - left) / 2;
top.val = nums[mid];
//当left<mid的时候,才能证明当前节点会有左子树,等于的话当前节点就不会有左右子树
//初始化左子树,压入左右值
if (left <mid) {
//处理左子树
top.left=new TreeNode(0);
nodeQueue.offer(top.left);
leftQueue.offer(left);
rightQueue.offer(mid-1);
}
if (right > mid) {
//处理右子树
top.right=new TreeNode(0);
nodeQueue.offer(top.right);
leftQueue.offer(mid+1);
rightQueue.offer(right);
}
}
return root;
}
把二叉搜索树转换为累加树
思路:
反序 右中左遍历即可.因为二叉搜索树的中序遍历(左中右)是升序无重复,那么最右边是这颗树的最大值(搜索树),所以从后往前遍历累加即可.
int sum = 0;
public TreeNode convertBST(TreeNode root) {
if (root == null) return null;
convertBST(root.right);
sum += root.val;
root.val = sum;
convertBST(root.left);
return root;
}
//morris遍历方法 正常morris序是往左一直遍历找前驱节点,这次试下往右遍历找后驱节点.
public TreeNode convertBST2(TreeNode root) {
if (root == null) return null;
int sum=0;
TreeNode cur = root;
TreeNode pre = null;
while (cur != null) {
TreeNode right = cur.right;
if (right != null) {
while (right.left != null && right.left != cur) {
right=right.left;
}
if(right.left==null){
right.left=cur;
cur=cur.right;
continue;
}else {
right.left = null;
}
}
sum+=cur.val;
cur.val=sum;
cur = cur.left;
}
return root;
}