算法题
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))
迭代法
因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。
在剪枝的时候,可以分为三步:
- 将root移动到[L, R] 范围内,注意是左闭右闭区间
- 剪枝左子树
- 剪枝右子树
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;elseroot = 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接近)
以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网