算法打卡day20|二叉树篇09|Leetcode 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

   算法题

Leetcode  669. 修剪二叉搜索树

题目链接:669. 修剪二叉搜索树

大佬视频讲解:修剪二叉搜索树视频讲解

个人思路

把这道题想复杂了,还想着如何去重构树

解法
递归法

依旧递归三步走

1.确定递归函数的参数以及返回值

这题递归需要返回值,因为是要遍历整棵树,做修改更方便,可以通过递归函数的返回值来移除节点

2.确定终止条件

修剪的操作并不是在终止条件上进行的,所以就是遇到空节点返回就可以了。

3.确定单层递归的逻辑

如果root(当前节点)的元素小于low的数值,那么应该递归右子树,并返回右子树符合条件的头结点。

如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点

如图:修剪区间[1,3] 将,0小于low,将0的右子树,返回给3节点的左子树。

class Solution {
    public 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;
    }
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(在最坏的情况下,当树是线性链表时(高度接近n),空间复杂度接近O(n))

迭代法

因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。

在剪枝的时候,可以分为三步:

  1. 将root移动到[L, R] 范围内,注意是左闭右闭区间
  2. 剪枝左子树
  3. 剪枝右子树
class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if(root == null)
            return null;
        while(root != null && (root.val < low || root.val > high)){
            if(root.val < low)
                root = root.right;
            else
                root = root.left;
        }

        TreeNode curr = root;
        
        //剪枝左子树
        while(curr != null){
            while(curr.left != null && curr.left.val < low){
                curr.left = curr.left.right;
            }
            curr = curr.left;
        }
        curr = root;//回溯

        //剪枝右子树
        while(curr != null){
            while(curr.right != null && curr.right.val > high){
                curr.right = curr.right.left;
            }
            curr = curr.right;
        }
        return root;
    }
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(最坏的情况下,算法的递归调用栈可能达到树的高度)


Leetcode 108.将有序数组转换为二叉搜索树

题目链接:108.将有序数组转换为二叉搜索树

大佬视频讲解:将有序数组转换为二叉搜索树视频讲解

个人思路

根据前面的题,构成二叉搜索树本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间,分割点就是数组中间位置的节点。

解法
递归法

首先先定义区间为左闭右闭区间

递归三步走:

1.确定递归函数返回值及其参数

删除二叉树节点,增加二叉树节点,都是用递归函数的返回值来完成,这样是比较方便的。

构造二叉树,依然用递归函数的返回值来构造中节点的左右孩子

参数的话,首先是传入数组,然后就是左下标left和右下标right,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组

2.确定递归终止条件

这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点

3.确定单层递归的逻辑

首先取数组中间元素的位置,不难写出int mid = (left + right) / 2;这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,所以可以这么写:int mid = left + ((right - left) >> 1);

取了中间位置,就开始以中间位置的元素构造节点

接着划分区间,root的左孩子接住下一层左区间的构造节点,右孩子接住下一层右区间构造的节点。

class Solution {
	public TreeNode sortedArrayToBST(int[] nums) {
		TreeNode root = traversal(nums, 0, nums.length - 1);
		return root;
	}

	// 左闭右闭区间[left, right]
	private TreeNode traversal(int[] nums, int left, int right) {
		if (left > right) return null;

        //取中间值;如果数组长度为偶数,中间位置有两个元素,取靠左边的
		int mid = left + ((right - left) >> 1);//不会越界的写法

		TreeNode root = new TreeNode(nums[mid]);
		root.left = traversal(nums, left, mid - 1);
		root.right = traversal(nums, mid + 1, right);
		return root;
	}
}

时间复杂度:O(n);(最差遍历一遍树)

空间复杂度:O(n);(递归树的高度h)

迭代法

通过三个队列来模拟,一个队列放遍历的节点,一个队列放左区间下标,一个队列放右区间下标。

class Solution {
	public TreeNode sortedArrayToBST(int[] nums) {
		if (nums.length == 0) return null;

		//根节点初始化
		TreeNode root = new TreeNode(-1);
		Queue<TreeNode> nodeQueue = new LinkedList<>();
		Queue<Integer> leftQueue = new LinkedList<>();
		Queue<Integer> rightQueue = new LinkedList<>();

		// 根节点入队列
		nodeQueue.offer(root);
		// 0为左区间下标初始位置
		leftQueue.offer(0);
		// nums.size() - 1为右区间下标初始位置
		rightQueue.offer(nums.length - 1);

		while (!nodeQueue.isEmpty()) {
			TreeNode currNode = nodeQueue.poll();
			int left = leftQueue.poll();
			int right = rightQueue.poll();
			int mid = left + ((right - left) >> 1);

			// 将mid对应的元素给中间节点
			currNode.val = nums[mid];

			// 处理左区间
			if (left <= mid - 1) {
				currNode.left = new TreeNode(-1);
				nodeQueue.offer(currNode.left);
				leftQueue.offer(left);
				rightQueue.offer(mid - 1);
			}

			// 处理右区间
			if (right >= mid + 1) {
				currNode.right = new TreeNode(-1);
				nodeQueue.offer(currNode.right);
				leftQueue.offer(mid + 1);
				rightQueue.offer(right);
			}
		}
		return root;
	}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(最坏的情况下,队列中可能需要存储整个输入数组的大小数量的节点)


Leetcode 538.把二叉搜索树转换为累加树

题目链接:538.把二叉搜索树转换为累加树

大佬视频讲解:把二叉搜索树转换为累加树视频讲解

个人思路

从题目所给例子树中,可以看出累加的顺序是右中左,所以反中序遍历这个二叉树,然后顺序累加就可以了。

解法
递归法

需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加

递归三步走:

1.递归函数参数以及返回值

不需要递归函数的返回值做什么操作,要遍历整棵树。

同时需要定义一个全局变量pre,用来保存cur节点的前一个节点的数值,定义为int型就可以了。

2.确定终止条件

遇空就终止。

3.确定单层递归的逻辑

注意右中左来遍历二叉树, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值

class Solution {
    int sum;
    public TreeNode convertBST(TreeNode root) {
        sum = 0;
        convertBST1(root);
        return root;
    }

    // 按右中左顺序遍历
    public void convertBST1(TreeNode root) {
        if (root == null) {
            return;
        }
        convertBST1(root.right);
        sum += root.val;//累加
        root.val = sum;
        convertBST1(root.left);
    }
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(递归树的高度,如果是一个高度不平衡的树(例如链状结构)高度与n接近)

迭代法

中序模板题,用栈模仿递归,遍历二叉树

class Solution {
    public TreeNode convertBST(TreeNode root) {
        int pre = 0;//遍历节点的前一个节点
        Stack<TreeNode> stack = new Stack<>();
        if(root == null)  return null;

        stack.add(root);

        while(!stack.isEmpty()){
            TreeNode curr = stack.peek();

            //curr != null的状况,只负责存node到stack中
            if(curr != null){ 
                stack.pop();
                if(curr.left != null)       //左
                    stack.add(curr.left);
                stack.add(curr);            //中
                stack.add(null);
                if(curr.right != null)      //右
                    stack.add(curr.right);
            }
            else{
            //curr == null的状况,只负责做单层逻辑
                stack.pop();
                TreeNode temp = stack.pop();
                temp.val += pre;
                pre = temp.val;
            }
        }
        return root;
    }
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(递归树的高度,如果是一个高度不平衡的树(例如链状结构)高度与n接近)


以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值