08. 将有序数组转换为二叉搜索树
简单
给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
输入:nums = [-10,-3,0,5,9] 输出:[0,-3,9,-10,null,5] 解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode root = traversal(nums,0,nums.length-1);
return root;
}
private TreeNode traversal(int[] nums, int left,int right){
if(left>right) return null;
int mid = (left+right)/2; //用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;
}
}
小结:
1. 二分法构建二叉树,注意统一区间,要不左闭右闭,隔离出mid [left,mid-1],mid,[mid+1,right]
如果左闭右开:[left,mid),mid,[mid+1,right)
2.这里需要构建,不能只是历遍,得到一个值,需要TreeNode root = new TreeNode(nums[mid])
root.left = traversal(````); root.right =traversal(```)
3.二分法求中值,保险的办法就是 mid = left+(right-left)/2 这样不会溢出。
4.新知识,mid=(left+right)>>1相当于mid=(left+right)/2 右移1就等于数学运算中的/2 同时运算速度更快 补充:
left + ((right -left) >> 1) == (left + right) /2
>>: 二进制右移
举个例子: 1010 >> 1 == 0101
1010 十进制 10
0101 十进制 5
综上 >> 1 作用相当于除二
所以 left + ((right -left) >> 1) ==> left + ((right -left)/2)
==> left + right/2 -left/2 ==> left/2 + right/2 ==> (left + right) /2
得证
问题 :为什么不直接用(left + right) /2 而用left + ((right -left) >> 1)
答: 是因为left + right 在某种情况下可能会超过基本类型所能容纳的最大值,而且 >> (位运算) 比 / 运算要快一点
450. 删除二叉搜索树中的节点
中等
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
示例 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]。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return root;
if(root.val==key){
if(root.left==null){
return root.right;
}
else if(root.right==null){
return root.left;
}
else{
TreeNode cur=root.right;
while(cur.left!=null){
cur=cur.left;
}
cur.left=root.left;
root =root.right;
return root;
}
}
else if(root.val>key){
root.left=deleteNode(root.left,key);
}else{
root.right=deleteNode(root.right,key);
}
return root;
}
}
小结:
1.二叉搜索树特性,就是左子树永远比根节点小,右子树永远比跟节点大
2.再理解迭代,roor.left 可以理解成root 这个节点,左边的整个分叉,因为往左可以一直迭代遍历
3.这道题关键点,在于最后一种情况,怎么嫁接枝干!
69. 修剪二叉搜索树
中等
给你二叉搜索树的根节点 root
,同时给定最小边界low
和最大边界 high
。通过修剪二叉搜索树,使得所有节点的值在[low, high]
中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。
所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。
示例 1:
输入:root = [1,0,2], low = 1, high = 2 输出:[1,null,2]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
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);
}else if(root.val>high){
return trimBST(root.left, low, high);
}else{
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
}
return root;
}
}
小结:
1.迭代,要知道return 是返回给上一层树节点,如果是两个函数,要注意对接
2.这里删除一个节点,不能直接return root.left or root.right =null;因为这样就会直接把整个root 的左或者右子树全部删除,实际是接着分析接下来的字数,递归接着修剪,最后返回给上一层