Leetcode1206(设计跳表)

news2025/1/12 23:16:44
例题:

分析:

我们先来找一找跳表与单链表的相同点和不同点。

相同点:

跳表和单链表一样,都是由一个一个的节点组成的链表。

不同点:

①:跳表中的元素已经是排好序的(图中从小到大),而链表中的元素对顺序没有要求,可以乱序。

②:跳表中的next指针可以有多个,可以分别指向不同的元素;而单链表只有一个next指针,只能指向离当前节点最近的元素。

不难发现,跳表在查询数据时有一个规律:

下楼梯方式查找

- 若next指针为null, 或者next指向的节点值 >= 目标值,则向下找

- 若next指针不为null, 且next指向的节点值 < 目标值,则向右找

可以先设计一个方法,根据节点值查找,并且记录所经过的节点路径:

        //查找指定节点并记录查询过程中所经过的节点
        public Node[] find(int val){
            Node curr = head;
            Node[] path = new Node[MAX];
            for(int level = MAX - 1; level >= 0; level--){  //向下找
                while (curr.next[level] != null && curr.next[level].value < val) { //向右找
                    curr = curr.next[level];
                }
                path[level] = curr;
            }
            return path;
        }

这段代码根据  curr.next[level].value < val 这个条件,我们最后找到的节点是目标节点的前一个节点,当然目标节点也可能不存在。这个方法在实现添加、删除方法时会经常用到。

注意:这里向下找的条件 和 向右找的条件是互斥的,所以不用再写一个向下找的判断逻辑

下图表示新加入一个节点

新加入节点时核心思想:

①:确定新加入节点的位置(把val当作目标查询,经过的路径就可以确定添加位置)

②:创建新节点随机高度,高度尽可能小(如果跳表的每个节点都很高,那么查询效率就低了)

③:修改新节点的next指针 和 路径节点的next指针

        static Random r = new Random();
        //随机返回 1~max 的数字
        /**
         * 从 1 开始,数字的几率逐级减半,例如 max = 4 ,让大概
         * - 50% 的几率返回 1
         * - 25% 的几率返回 2
         * - 12.5% 的几率返回 3
         * - 12.5% 的几率返回 4
         */
        static int randomLevel(int max){
            int x = 1;
            while(x < max){
                if(r.nextBoolean()){
                    return x;
                }
                x++;
            }
            return x;
        }

        //添加节点
        public void add(int num) {
            //1.确定新加入节点的位置(把val当作目标查询,经过的路径就可以确定添加位置)
            Node[] path = find(num);
            //2.创建新节点随机高度,高度尽可能小
            Node node = new Node(num);
            int level = randomLevel(MAX);
            //3.修改新节点的next指针, 路径节点的next指针
            for(int i = 0; i < level; i++){
                node.next[i] = path[i].next[i];
                path[i].next[i] = node;
            }
        }

完整代码:
package leetcodeup;

import java.util.Random;

public class SkipListLeetcode1206 {

    static class Skiplist {

        private static final int MAX = 10;  //节点的最大next指针数
        private final Node head = new Node(-1); //头节点

        static Random r = new Random();
        //随机返回 1~max 的数字
        /**
         * 从 1 开始,数字的几率逐级减半,例如 max = 4 ,让大概
         * - 50% 的几率返回 1
         * - 25% 的几率返回 2
         * - 12.5% 的几率返回 3
         * - 12.5% 的几率返回 4
         */
        static int randomLevel(int max){
            int x = 1;
            while(x < max){
                if(r.nextBoolean()){
                    return x;
                }
                x++;
            }
            return x;
        }

        static class Node{
            int value;
            Node[] next = new Node[MAX];

            public Node(int value) {
                this.value = value;
            }
        }

        //查找指定节点并记录查询过程中所经过的节点
        public Node[] find(int val){
            Node curr = head;
            Node[] path = new Node[MAX];
            for(int level = MAX - 1; level >= 0; level--){  //向下找
                while (curr.next[level] != null && curr.next[level].value < val) { //向右找
                    curr = curr.next[level];
                }
                path[level] = curr;
            }
            return path;
        }

        //查找节点
        public boolean search(int target) {
            Node[] path = find(target);
            Node node = path[0].next[0];
            return node != null && node.value == target;
        }

        //添加节点
        public void add(int num) {
            //1.确定新加入节点的位置(把val当作目标查询,经过的路径就可以确定添加位置)
            Node[] path = find(num);
            //2.创建新节点随机高度,高度尽可能小
            Node node = new Node(num);
            int level = randomLevel(MAX);
            //3.修改新节点的next指针, 路径节点的next指针
            for(int i = 0; i < level; i++){
                node.next[i] = path[i].next[i];
                path[i].next[i] = node;
            }
        }

        //删除节点
        public boolean erase(int num) {
            Node[] path = find(num);
            Node node = path[0].next[0];
            //要删除的节点可能不存在
            if(node == null || node.value != num){
                return false;
            }
            //节点存在,开始删除节点
            for(int i = 0; i < MAX; i++){
                if(path[i].next[i] != node){
                    break;
                }
                path[i].next[i] = node.next[i];
            }
            return true;
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1459424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

突破性创新:OpenAI推出Sora视频模型,预示视频制作技术的未来已到来!

一、前言 此页面上的所有视频均由 Sora 直接生成&#xff0c;未经修改。 OpenAI - Sora is an AI model that can create realistic and imaginative scenes from text instructions. 2024 年 2 月 16 日&#xff0c;OpenAI 发布 AI 视频模型 Sora&#xff0c;60 秒的一镜到底…

STM32-启用蜂鸣器

目录 1 、电路构成及原理图 2、编写实现代码 main.c beep.c beep.h 3、代码讲解 4、 烧录到开发板调试、验证代码 5、检验效果 本人使用的是朗峰 STM32F103 系列开发板&#xff0c;此笔记基于这款开发板记录。 1 、电路构成及原理图 首先&#xff0c;通过朗峰 F1 开…

VILT算法解读

VILT是一种典型的单塔结构&#xff0c;不同于双塔结构由两个独立的Image Encoder以及Text Encoder组成&#xff08;比如clip&#xff09;&#xff0c;单塔结构的模型一般只有一个共用的编码器&#xff0c;称为Multi-Modal Encoder。 1、VILT算法原理 VILT被认为是最简单的…

SpringBoot中使用PageHelper插件实现Mybatis分页

场景 SpringBoot中整合Mybatis时一般添加的依赖为 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.1</version></dependency> 如果要实现分页查…

PostgreSQL按日期列创建分区表

在PostgreSQL中&#xff0c;实现自动创建分区表主要依赖于表的分区功能&#xff0c;这一功能从PostgreSQL 10开始引入。分区表可以帮助管理大量数据&#xff0c;通过分布数据到不同的分区来提高查询效率和数据维护的便捷性。以下是在PostgreSQL中自动创建分区表的一般步骤&…

docker之安装mongo创建运行环境

目录 一、docker pull 最新资源 二、启动mongo镜像 启动命令查看日志拉取低版本镜像成功启动 三、进入mongo容器 进入容器进入mongo环境查询当前所在库切换库至admin随意切换库 并 创建用户登录用户新增文档数据等 五、总结 版本兼容可备份操作 一、docker pull 最新资源…

java面试集合篇

上面是java中集合的整体框架图。 集合使用的数据结构 算法复杂度分析 时间复杂度分析 时间复杂度分析&#xff1a;来评估代码的执行耗时的 /*** 求1~n的累加和* param n* return*/ public int sum(int n) {int sum 0;for ( int i 1; i < n; i) {sum sum i;}return …

【常识】大数据设计基础知识

底层存储&#xff1a;hadoop&#xff08;hdfsmapreduce&#xff09; Hadoop已经有十几年的历史&#xff0c;它是大数据领域的存储基石&#xff0c;HDFS目前仍然没有成熟替代品;MapR 文件系统在业内已经具有一定知名度了&#xff0c;不仅 MapR 宣布它自己的文件系统比 HDFS 快2-…

模板(函数模板)---C++

模板目录 模板1.模板概念&#xff12;.泛型编程 1.函数模板1.1 函数模板语法1.2 函数模板注意事项1.3 普通函数与函数模板的区别1.4 普通函数与函数模板的调用规则1.5 模板的局限性1.6 函数模板案例 模板 1.模板概念 模板就是建立通用的模具&#xff0c;大大提高复用性。 模板…

如何在本地服务器部署TeslaMate并远程查看特斯拉汽车数据无需公网ip

文章目录 1. Docker部署TeslaMate2. 本地访问TeslaMate3. Linux安装Cpolar4. 配置TeslaMate公网地址5. 远程访问TeslaMate6. 固定TeslaMate公网地址7. 固定地址访问TeslaMate TeslaMate是一个开源软件&#xff0c;可以通过连接特斯拉账号&#xff0c;记录行驶历史&#xff0c;统…

解决Edge浏览器,微博无法查看大图(Edge Image Viewer)

使用Edge浏览器浏览微博或其它带校验的图片时&#xff0c;会导致无法查看。 主要原因为Edge自带了一个Edge Image Viewer, 但是该图片查看器无法查看带校验数据的图片&#xff0c;所以导致查看时一片空白。 解决方法 地址栏输入 edge://flags/搜索 Edge Image Viewer选择 Disa…

爬虫学习笔记-scrapy爬取电影天堂(双层网址嵌套)

1.终端运行scrapy startproject movie,创建项目 2.接口查找 3.终端cd到spiders,cd scrapy_carhome/scrapy_movie/spiders,运行 scrapy genspider mv https://dy2018.com/ 4.打开mv,编写代码,爬取电影名和网址 5.用爬取的网址请求,使用meta属性传递name ,callback调用自定义的…

JVM原理学习

一.栈上的数据存储P95 二.堆上的数据存储 标记字段 指针压缩(节省空间 内存对齐(提高CPU缓存行效率 字段重排列方便内存对齐 类排在基本类型之后 三.JIT实时编译 优化手段 C2编译器&#xff0c;直接将循环相加求和优化为乘法。 方法内联 逃逸分析 四.G1垃圾回收器原理 年轻代…

Vue | (三)使用Vue脚手架(中)| 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;Todo-list 案例&#x1f407;组件化编码流程&#xff08;通用&#xff09;&#x1f407;实现静态组件&#x1f407;展示动态数据&#x1f407;交互⭐️添加一个todo⭐️todo勾选实现⭐️删除功能实现⭐️底部统计功能实现⭐️底部全选功能实现⭐️底部一…

Vue报错,xxx is defined #变量未定义

vue.js:5129 [Vue warn]: Error in v-on handler: "ReferenceError: count is not defined" 浏览器将这个变量 当做全局变量了&#xff0c;事实上它只是实例中的变量 加上this指定&#xff0c;是vue实例中的变量

Android之Android.bp文件格式语法(一百八十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

代码随想录算法训练营day20

题目&#xff1a;530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先 参考链接&#xff1a;代码随想录 530.二叉搜索树的最小绝对差 思路&#xff1a;我一开始想到的方法是先生成中序序列&#xff0c;然后对相邻两项的差进行计算&#xff0c;取…

代码随想录刷题笔记-Day21

1. 二叉搜索树中的插入操作 701. 二叉搜索树中的插入操作https://leetcode.cn/problems/insert-into-a-binary-search-tree/给定二叉搜索树&#xff08;BST&#xff09;的根节点 root 和要插入树中的值 value &#xff0c;将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。…

聊聊 Git SubModule(子模块)

比如在公司不同开发团队中&#xff0c;有一个基础共享库&#xff0c;同时被多个项目调用。若要保证基础共享库的动态更新&#xff0c;那么就需要把共享库独立为一个代码库&#xff0c;但是分别把共享库中的文件拷贝到各自的项目中会造成冗余&#xff0c;而且再次更新共享库就会…

提升认知水平和防止偏见浅谈

提升认知水平和防止偏见浅谈 《庄子外物》&#xff1a;井蛙不可语海&#xff0c;夏虫不可语冰。 不要跟井底的青蛙谈论大海&#xff0c;因为它的认知只有井底那么大&#xff0c;大海对于它来说是认知盲区&#xff1b;不要与夏虫去谈论冰雪&#xff0c;因为夏虫一生很短没有经历…