代码随想录算法Day23 | 669. 修剪二叉搜索树 ,108.将有序数组转换为二叉搜索树 , 538.把二叉搜索树转换为累加树 , 总结篇
669. 修剪二叉搜索树
题目链接:669. 修剪二叉搜索树 - 力扣(LeetCode)
思路
在 删除二叉搜索树中节点值为key的节点 这一题中,分五种情况来考虑,找到节点后删除即可。
而这道题是要求删除所有不在[low, high]之间的节点。
最简单的方法,遍历所有节点,如果不在low, high]范围,返回null。
但这种方法存在一定问题。
按照这种方法,会直接删除以该节点为根的树,如果这个树中此时还存在符合low, high]范围的节点的话,也会 被删除。如图所示。

所以该方法不可行,但在上图中我们发现节点0并不符合区间要求,那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了(就是把节点0从二叉树中移除)。
因此我们可以得到单层递归的逻辑。
- 如果root(当前节点)的元素小于low的数值,那么应该递归右子树(二叉搜索树特性,右子树的节点大于当前节点),并返回右子树符合条件的头结点。
- 如果root(当前节点)的元素大于high的,那么应该递归左子树(二叉搜索树特性,左子树的节点小于当前节点),并返回左子树符合条件的头结点。
- 接下来要将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。
代码
递归法
1 class Solution { 2 public TreeNode trimBST(TreeNode root, int low, int high) { 3 if (root == null) { 4 return null; 5 } 6 if (root.val < low) { 7 return trimBST(root.right, low, high); 8 } 9 if (root.val > high) { 10 return trimBST(root.left, low, high); 11 } 12 // root在[low,high]范围内 13 root.left = trimBST(root.left, low, high); 14 root.right = trimBST(root.right, low, high); 15 return root; 16 } 17 }
迭代法
因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。
在剪枝的时候,可以分为三步:
- 将root移动到[L, R] 范围内,注意是左闭右闭区间
- 剪枝左子树
- 剪枝右子树
代码如下:
1 class Solution { 2 public TreeNode trimBST(TreeNode root, int low, int high) { 3 if (root == null){ 4 return null; 5 } 6 // 处理头结点不在[low,high]范围内的情况,让 root 移动到[low,high]范围内 7 while (root != null && (root.val < low || root.val > high)){ 8 // 进入循环的root的值只有两种情况, 小于 low 或者 大于 high 9 if (root.val < low) { 10 root = root.right; // 小于low,根据搜索树特性,往右走。 11 } else { 12 root = root.left;// 大于high,往左走。 13 } 14 } 15 16 TreeNode cur = root; 17 // 处理 root 左孩子元素小于low的情况 18 while (cur != null){ 19 while (cur.left != null && cur.left.val < low) { 20 cur.left = cur.left.right; 21 } 22 cur = cur.left; 23 } 24 25 cur = root; 26 // 处理 root 右孩子小于high的情况 27 while (cur != null){ 28 while (cur.right != null && cur.right.val > high) { 29 cur.right = cur.right.left; 30 } 31 cur = cur.right; 32 } 33 34 return root; 35 } 36 }
108.将有序数组转换为二叉搜索树
题目链接:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
思路
这道题本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。
分割点就是数组中间位置的节点。(当数组长度为偶数时,中间元素有两个,不同的选择也对应两种不同答案)
代码
1 // 递归: 左闭右开 [left,right) 2 class Solution { 3 public TreeNode sortedArrayToBST(int[] nums) { 4 return sortedArrayToBST(nums, 0, nums.length); 5 } 6 7 public TreeNode sortedArrayToBST(int[] nums, int left, int right) { 8 if (left >= right) { 9 return null; 10 } 11 if (right - left == 1) { 12 return new TreeNode(nums[left]); 13 } 14 int mid = left + (right - left) / 2; 15 TreeNode root = new TreeNode(nums[mid]); 16 root.left = sortedArrayToBST(nums, left, mid); 17 root.right = sortedArrayToBST(nums, mid + 1, right); 18 return root; 19 } 20 }
1 // 递归: 左闭右闭 [left,right] 2 class Solution { 3 public TreeNode sortedArrayToBST(int[] nums) { 4 TreeNode root = traversal(nums, 0, nums.length - 1); 5 return root; 6 } 7 8 // 左闭右闭区间[left, right] 9 private TreeNode traversal(int[] nums, int left, int right) { 10 if (left > right) return null; 11 12 int mid = left + ((right - left) >> 1); 13 TreeNode root = new TreeNode(nums[mid]); 14 root.left = traversal(nums, left, mid - 1); 15 root.right = traversal(nums, mid + 1, right); 16 return root; 17 } 18 }
1 // 迭代: 左闭右闭 [left,right] 2 class Solution { 3 public TreeNode sortedArrayToBST(int[] nums) { 4 if (nums.length == 0) return null; 5 6 //根节点初始化 7 TreeNode root = new TreeNode(-1); 8 Queue<TreeNode> nodeQueue = new LinkedList<>(); 9 Queue<Integer> leftQueue = new LinkedList<>(); 10 Queue<Integer> rightQueue = new LinkedList<>(); 11 12 // 根节点入队列 13 nodeQueue.offer(root); 14 // 0为左区间下标初始位置 15 leftQueue.offer(0); 16 // nums.size() - 1为右区间下标初始位置 17 rightQueue.offer(nums.length - 1); 18 19 while (!nodeQueue.isEmpty()) { 20 TreeNode currNode = nodeQueue.poll(); 21 int left = leftQueue.poll(); 22 int right = rightQueue.poll(); 23 int mid = left + ((right - left) >> 1); 24 25 // 将mid对应的元素给中间节点 26 currNode.val = nums[mid]; 27 28 // 处理左区间 29 if (left <= mid - 1) { 30 currNode.left = new TreeNode(-1); 31 nodeQueue.offer(currNode.left); 32 leftQueue.offer(left); 33 rightQueue.offer(mid - 1); 34 } 35 36 // 处理右区间 37 if (right >= mid + 1) { 38 currNode.right = new TreeNode(-1); 39 nodeQueue.offer(currNode.right); 40 leftQueue.offer(mid + 1); 41 rightQueue.offer(right); 42 } 43 } 44 return root; 45 } 46 }
538.把二叉搜索树转换为累加树
题目链接:538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)
思路
这道题可以理解成一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13]。从后往前挨个累加即可。
那么我们就可以知道如何遍历这个二叉树,从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了。
代码
递归法
1 class Solution { 2 int sum; 3 public TreeNode convertBST(TreeNode root) { 4 sum = 0; 5 convertBST1(root); 6 return root; 7 } 8 9 // 按右中左顺序遍历,累加即可 10 public void convertBST1(TreeNode root) { 11 if (root == null) { 12 return; 13 } 14 convertBST1(root.right); 15 sum += root.val; 16 root.val = sum; 17 convertBST1(root.left); 18 } 19 }
迭代法
1 class Solution { 2 public TreeNode convertBST(TreeNode root) { 3 if (root == null){ 4 return null; 5 } 6 // 记录前一个节点的数值 7 int pre = 0; 8 Deque<TreeNode> stack = new LinkedList<>(); 9 TreeNode cur = root; 10 while (cur != null || !stack.isEmpty()){ 11 if (cur != null){ 12 stack.push(cur); 13 cur = cur.right; // 右 14 } else { 15 cur = stack.pop(); // 中 16 cur.val += pre; 17 pre = cur.val; 18 cur = cur.left; // 左 19 } 20 } 21 return root; 22 } 23 }

浙公网安备 33010602011771号