Leetcode 刷题笔记(十八) —— 二叉树篇之二叉搜索树的修改与构造

文章目录

  • 系列文章目录
  • 前言
  • 题录
    • 701. 二叉搜索树中的插入操作
    • 450. 删除二叉搜索树中的节点
    • 669. 修剪二叉搜索树
    • 108. 将有序数组转换为二叉搜索树
    • 538. 把二叉搜索树转换为累加树

系列文章目录

一、 数组类型解题方法一:二分法
二、数组类型解题方法二:双指针法
三、数组类型解题方法三:滑动窗口
四、数组类型解题方法四:模拟
五、链表篇之链表的基础操作和经典题目
六、哈希表篇之经典题目
七、字符串篇之经典题目
八、字符串篇之 KMP
九、解题方法:双指针
十、栈与队列篇之经典题目
十 一、栈与队列篇之 top-K 问题
十 二、二叉树篇之二叉树的前中后序遍历
十 三、二叉树篇之二叉树的层序遍历及相关题目
十 四、二叉树篇之二叉树的属性相关题目
十 五、 二叉树篇之二叉树的修改与构造
十 六、 二叉树篇之二叉搜索树的属性
十 七、二叉树篇之公共祖先问题
更新中 …


前言

刷题路线来自 :代码随想录

题录

701. 二叉搜索树中的插入操作

Leetcode 链接
给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

示例 1:
输入:root = [4,2,7,1,3], val = 5
输出:[4,2,7,1,3,5]
解释:另一个满足题目要求可以通过的树是:

示例 2:
输入:root = [40,20,60,10,30,50,70], val = 25
输出:[40,20,60,10,30,50,70,null,null,25]

示例 3:
输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5
输出:[4,2,7,1,3,5]

题解:
按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了
方式一:递归
利用返回值完成新加入的节点与其父节点的赋值操作,

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) return new TreeNode(val);
        // 本层用root->left或者root->right将其接住下一层返回的结点
        // 下层返回结点的可能:
        // 1.向下递归时遇见空结点,即可返回构造好的 val 结点
        // 2.向上回溯时返回
        if (val < root.val) root.left = insertIntoBST(root.left, val);
        if (val > root.val) root.right = insertIntoBST(root.right, val);
        return root;
    }
}

方式二:迭代法
遍历到 null 时加入新节点,需要知道父亲结点,所以使用一个结点保存父亲结点

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) return new TreeNode(val);
        TreeNode cur = root;
        TreeNode pre = root;
        while (cur != null) {
        	// 保存父亲结点
            pre = cur;
            // 寻找插入位置
            if (val > cur.val) {
                cur = cur.right;
            } else if (val < cur.val) {
                cur = cur.left;
            }
        }
		// 此时不知道插入位置是父亲结点的左还是右,需要判断一下
        if (val < pre.val) {
            pre.left = new TreeNode(val);
        } else {
            pre.right = new TreeNode(val);
        }
        return root;
        
    }
}

450. 删除二叉搜索树中的节点

Leetcode 链接
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。

示例 1:
Leetcode 刷题笔记(十八) —— 二叉树篇之二叉搜索树的修改与构造_第1张图片

输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]
解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
另一个正确答案是 [5,2,6,null,4,null,7]。

示例 2:
输入: root = [5,3,6,2,4,null,7], key = 0
输出: [5,3,6,2,4,null,7]
解释: 二叉树不包含值为 0 的节点

示例 3:
输入: root = [], key = 0
输出: []

题解:

  1. 删除结点没有子节点
  2. 删除结点没有右结点
  3. 删除结点没有左结点
  4. 删除结点有左右结点,前三种好处理。示例1 中如果删除根节点 5 ,需要将左子树移动到右子树的,结点 6 的左结点上。
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        if (root == null) return root;
        if (key < root.val) {
            root.left = deleteNode(root.left, key);
        } else if (key > root.val) {
            root.right = deleteNode(root.right, key);
        } else {
            // 找到删除的结点了
            TreeNode left = root.left;
            // 右结点空,返回左结点 左结点,返回右结点
            if (root.right == null) {
                return root.left;
            } else if (root.left == null) {
                return root.right;
            } else {
            	// 左右都不为空,将左子树放到右子树的适当位置上
                TreeNode cur = root.right;
                // 找到右子树的最左边
                while (cur.left != null) {
                    cur = cur.left;
                }
                cur.left = left;
                return root.right;
            }
        }
        return root;
    }
}

669. 修剪二叉搜索树

Leetcode 链接
给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

示例 1:
输入:root = [1,0,2], low = 1, high = 2
输出:[1,null,2]

示例 2:
输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3
输出:[3,2,null,1]

题解:
错误解:直接 root == null || root.val < low || root.val > high 就 return null,0 虽然小于 1 但是不能直接将左子树全部移除
Leetcode 刷题笔记(十八) —— 二叉树篇之二叉搜索树的修改与构造_第2张图片

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null || root.val < low || root.val > high) return null;
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
    }
}

方式一:递归法

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return root;
        if (root.val < low) {
         	// 0 小于 1,跳过左子树,直接去递归大于 0 的右子树,返回的适合相当于跳过了这一层结点
            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;
    }
}

方式二:迭代法

class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return root;
         // 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
        while (root != null && (root.val < low || root.val > high)) {
            if (root.val < low) {
                root = root.right;
            } else {
                root = root.left;
            }
        }
        // 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
        TreeNode cur = root;
        while (cur != null) {
        	// 同示例二
            while (cur.left != null && cur.left.val < low) {
                cur.left = cur.left.right;
            }
            cur = cur.left;
        }
        // 此时root已经在[L, R] 范围内,处理右孩子大于R的情况
        cur = root;
        while (cur != null) {
            while (cur.right != null && cur.right.val > high) {
                cur.right = cur.right.left;
            }
            cur = cur.right;
        }
        return root;
    }
}

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

Leetcode 链接
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树。

题解:
回顾 二叉树篇之二叉树的修改与构造

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return build(nums, 0, nums.length);
    }
    public TreeNode build(int[] nums, int left, int right) {
    	// 区间内没有结点
        if (right - left <= 0) {
            return null;
        }
        // 区间内只剩一个结点
        if (right - left == 1) {
            return new TreeNode(nums[left]);
        }
        // 每次将中间结点作为根节点
        int mid = left + (right - left) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = build(nums, left, mid);
        root.right = build(nums, mid + 1, right);
        
        return root;
    }
}

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

Leetcode 链接
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。

Leetcode 刷题笔记(十八) —— 二叉树篇之二叉搜索树的修改与构造_第3张图片
输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

题解:

中序遍历

class Solution {
    public TreeNode convertBST(TreeNode root) {
        dfs(root);
        return root;
    }
    int sum = 0;
    public void dfs(TreeNode root) {
        if (root == null) return;
        // 左
        dfs(root.right);
        // 中
        sum += root.val;
        root.val = sum;
        // 右
        dfs(root.left);
    }
}

你可能感兴趣的:(算法,leetcode,算法,二叉树,数据结构)