代码随想录算法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 }

 

posted @ 2023-02-23 19:22  颜欢兮  阅读(16)  评论(0)    收藏  举报