IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【算法之LeetCode系列(6)】—— 二叉搜索树(BST) -> 正文阅读

[数据结构与算法]【算法之LeetCode系列(6)】—— 二叉搜索树(BST)

LeetCode之二叉搜索树系列

昨天我的二叉树系列突然上榜了(《数据结构与算法领域内容榜》),最高18名,很意外,感谢官方大大 #CSDN 的支持。

计划着按照la哥的建议,先干二叉树,所以前面做了一下简单的二叉树,捡回了一些知识,直观感受就是做这类题至少有了一个大致的思路,普通的二叉树、平衡二叉树了解了一些,今天来干二叉搜索树。

二叉搜索树( BST )是神马东东?

我的理解就是,一颗二叉树的中序遍历结果是一个递增序列,这就是二叉搜索树

三道题

1. 有序数组转高度平衡的 BST
2. 有序链表转高度平衡的 BST
3. BST 中的搜索

题目描述移步力扣官网哈

1. 有序数组转高度平衡的 BST

给一个严格递增的数组(符合我上面说的,中序遍历后是一个递增序列,现在就是把这个序列给变回去,变成BST),我当时的第一想法是,既然要满足二叉搜索树的定义,那么数组的最中间的元素一定是根节点(或者与中间元素的距离等于1),因为还要满足高度平衡,高度差不能超过1,这样根节点有了。
左子树和右子树怎么办?
左右子树不还是一样,一样要找根节点,只要是根节点,那就和上面的找法没区别,所以相当于是数组不断的被分隔成两部分,这不就是递归该出场了吗?(分治也可以)

var sortedArrayToBST = function(nums) {
    function insertNode(nums,left,right){
    	//左边大于右边,说明已经没有后续元素需要插入了
        if(left > right){
            return null;
        }
        //取中间位置的做法还有 mid = (left + right) >>> 1;
        let mid = Math.floor((left + right) / 2);
        //如上所说,只要是根节点,就以中间元素作为它的值
        let root = new TreeNode(nums[mid]);
        //划分数组左区间构建左子树
        root.left = insertNode(nums,left,mid - 1);
        //划分数组右区间构建右子树
        root.right = insertNode(nums,mid + 1,right);
        return root;
    }
    return insertNode(nums,0,nums.length - 1);
};

2. 有序链表转高度平衡的 BST

我相信看到这个题,大家一定和我一样聪明(我不是)想着直接把有序链表转成有序数组,就神奇的变成上一个题了,但是呢,这确实有点投机取巧,所以当然还有其他办法呀
提前剧透:方法二:快慢指针,方法三:中序遍历
(我怎么可能想出来呢,当然是各位大佬的意思,我只是来说说我对这两种方法的理解的)
方法二三来自
作者:xiao_ben_zhu
链接:https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/solution/shou-hua-tu-jie-san-chong-jie-fa-jie-

//    方法一(转数组,就不解释了)
var sortedListToBST = function(head) {

	let nums= [];
    while(null !== head){
        nums.push(head.val);
        head = head.next;
    }
    let insertNode = (nums,low,high)=>{
        if(low > high)  return null;
        let mid = Math.floor((low + high) / 2);
        let root = new TreeNode(nums[mid]);
        root.left = insertNode(nums,low,mid - 1);
        root.right = insertNode(nums,mid + 1,high);
        return root;
    }
    return insertNode(nums,0,nums.length - 1)
};
// 方法二(快慢指针)
var sortedListToBST = function(head) {

	//如果是空树或者当前节点是叶子节点,返回null
    if (head == null) return null;
    //维护快慢指针,初始值是head
    let slow = head;
    let fast = head;
    // 保存slow的前一个节点,这个慢指针前驱很关键
    //作用就相当于是把链表切成左右两部分的刀,每次都是它切,每次slow找到中间节点,它就得切一次,保证区间再次化小,递归构建子树
    let preSlow;
	//快慢指针真的妙。你看啊,同样的距离,每次我走两步,你走一步,那等我走完,你是不是刚好在中间呢,妙!
    while (fast && fast.next) {//fast走到尾部就是找到中间节点的时刻
        preSlow = slow;        // 保存当前slow
        slow = slow.next;      // slow走一步
        fast = fast.next.next; // fast走两步
    }
    const root = new TreeNode(slow.val);     // 根据slow指向的节点值(就是链表的中间节点),构建节点
	
    if (preSlow != null) {   // 如果preSlow有值,即slow左边有节点,需要构建左子树
        preSlow.next = null;   // 切断preSlow和中点slow
        //这个preslow就相当于是切完了,然后再重新构建一个二叉搜索树,只不过呢,这棵树是刚刚根节点的左子树
        root.left = sortedListToBST(head);     // 然后递归构建左子树(就是重复构建后面每个节点的左子树)
    }
    root.right = sortedListToBST(slow.next); // 递归构建右子树,这个就是右半部分,用来重复构建每个节点的右子树
    return root;
};
//    方法三(中序遍历)

不需要找中间节点,遇到哪个节点,就把哪个节点当做根节点,就是一直构建一个只有三个节点的二叉树,然后,构建完一颗就连上下一个合适的根节点

var sortedListToBST = function(head) {
	if(head === null)return null;
    let h = head;//构建节点的关键指针
    let len = 0;
    while(head){
        len ++;
        head = head.next;
    }
    const buildBST = (start, end)=>{
        if(start > end) return null;//当不能再二分,就说明这是最底部的空节点
        let mid = (start + end) >>> 1;//只是单纯的二分一下,用于分别构建左右子树
        let left = buildBST(start,mid - 1);//按照中序遍历的顺序,先构建左子树
        let root = new TreeNode(h.val);//创建根节点
        h = h.next;//不断后移,为每棵小树创建节点
        root.left = left;//连上左子树
        root.right = buildBST(mid + 1,end);//连上右子树
        return root;
    }
    return buildBST(0,len - 1);
};

3. BST 中的搜索

这就是在一个有序序列里找数字的游戏,很简单,假如是递增序列,每次比较中间元素mid,比mid大的丢到后半区间找,比mid小的丢到前半区间找,思路应该很清晰

var searchBST = function(root, val) {
    while(root !== null){//只要当前进入的根节点不是空的,就说明我还有可能!!!
        if(root.val === val){
            return root;
        }else if(root.val > val){//目标值比根节点小,丢到左区间
            return searchBST(root.left, val);
        }else if(root.val < val){//目标值比根节点大,丢到右区间
            return searchBST(root.right, val);
        }
    }
    return null
};

本来还想再写两个个题的,但是能力有限,我自己都没明白呢,就不瞎写了,下次见(下次直接加在这里面,所以建议收藏本文哦)!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-09-06 11:24:08  更:2021-09-06 11:25:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:47:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码