Leetcode1206:设计跳表

题目描述:

不使用任何库函数,设计一个 跳表

跳表 是在 O(log(n)) 时间内完成增加、删除、搜索操作的数据结构。跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。

例如,一个跳表包含 [30, 40, 50, 60, 70, 90] ,然后增加 8045 到跳表中,以下图的方式操作:

跳表中有很多层,每一层是一个短的链表。在第一层的作用下,增加、删除和搜索操作的时间复杂度不超过 O(n)。跳表的每一个操作的平均时间复杂度是 O(log(n)),空间复杂度是 O(n)

了解更多 : 跳表 - OI Wiki

在本题中,你的设计应该要包含这些函数:

  • bool search(int target) : 返回target是否存在于跳表中。
  • void add(int num): 插入一个元素到跳表。
  • bool erase(int num): 在跳表中删除一个值,如果 num 不存在,直接返回false. 如果存在多个 num ,删除其中任意一个即可。

注意,跳表中可能存在多个相同的值,你的代码需要处理这种情况。

代码思路:

跳表是一种随机化的数据结构,允许快速查找、插入和删除操作。它通过多层链表实现,每一层都是前一层的子集,且最高层的链表最短。查找、插入和删除操作从最顶层开始,逐层向下进行,直到找到或操作完成于最底层。

跳表类(Skiplist)主要方法思路:
  1. 初始化(__init__
    • 创建一个头节点(值为负无穷大),一个尾节点(值为正无穷大),并将头节点的next列表的第一个元素指向尾节点。
    • 初始化跳表的最高层数为0。
  2. 查找(search
    • 从最高层开始,逐层向下查找目标值。
    • 在每一层中,通过比较目标值和当前节点的下一个节点的值来移动指针。
    • 如果找到目标值,返回True;如果遍历完所有层仍未找到,返回False
  3. 添加(add
    • 从最高层开始,逐层向下找到插入位置,并记录路径。
    • 在最底层(第0层)插入新节点。
    • 使用概率为1/2的随机抛硬币决定是否将新节点提升到更高层。
    • 如果提升到比当前最高层还高的层,需要更新头节点的next列表和新节点的next列表,并增加跳表的最高层数。
  4. 删除(erase
    • 从最高层开始,逐层向下查找目标值。
    • 在每一层中,如果找到目标值,将其从链表中删除,并标记操作成功。
    • 返回操作是否成功的标志。

代码实现:

复制代码
import random

class Node:

    def __init__(self, val):
        self.val = val  # 节点值
        self.next = []  # 指向下一节点的列表,不同层对应不同节点

class Skiplist:

    def __init__(self):
        self.head = Node(-float('inf'))  # 头节点,值为负无穷大
        self.tail = Node(float('inf'))  # 尾节点,值为正无穷大
        self.head.next.append(self.tail)  # 头节点指向尾节点
        self.levels = 0  # 最高层数

    def search(self, target: int) -> bool:
        # 类似于add方法
        level = self.levels  # 从最高层开始
        cur = self.head  # 当前节点从头节点开始
        while level != -1:
            while target > cur.next[level].val:
                cur = cur.next[level]  # 移动到下一个节点
            if target == cur.next[level].val:
                return True  # 找到目标值
            level -= 1  # 移动到下一层
        return False  # 未找到目标值

    def add(self, num: int) -> None:
        level = self.levels  # 从最高层开始
        path = []  # 记录路径,用于后续提升
        cur = self.head  # 当前节点从头节点开始
        while level != -1:
            while num >= cur.next[level].val:
                cur = cur.next[level]  # 移动到下一个节点
            path.append(cur)  # 记录当前路径节点
            level -= 1  # 移动到下一层
        node = Node(num)  # 创建新节点
        # 在第0层插入新节点
        node.next.append(path[-1].next[0])
        path[-1].next[0] = node
        # 尝试提升新节点
        def coin_flip():
            return random.random() > 0.5  # 抛硬币,返回True或False
        level = 1  # 从第1层开始尝试提升
        while coin_flip():
            if level > self.levels:
                self.head.next.append(node)  # 更新头节点指向新节点
                node.next.append(self.tail)  # 新节点指向尾节点
                self.levels += 1  # 增加最高层数
            else:
                i = len(path) - 1 - level  # 计算路径中对应层的节点索引
                node.next.append(path[i].next[level])
                path[i].next[level] = node
            level += 1  # 尝试提升到下一层

    def erase(self, num: int) -> bool:
        level = self.levels  # 从最高层开始
        cur = self.head  # 当前节点从头节点开始
        flag = False  # 操作成功标志
        while level != -1:
            while num > cur.next[level].val:
                cur = cur.next[level]  # 移动到下一个节点
            if cur.next[level].val == num:
                flag = True  # 找到目标值,标记操作成功
                cur.next[level] = cur.next[level].next[level]  # 从链表中删除目标节点
            level -= 1  # 移动到下一层
        return flag  # 返回操作成功标志
相关推荐
小蒋学算法3 分钟前
算法-灌溉花园的最少龙头数目-贪心
算法
满怀冰雪4 分钟前
第07篇-差分算法-高效处理区间修改问题
数据结构·算法
KaMeidebaby6 分钟前
卡梅德生物技术快报|重组蛋白的表达和纯化:工艺调试全记录:大肠杆菌体系重组蛋白的表达和纯化参数标定(肠激酶轻链案例)
前端·人工智能·算法·数据挖掘·数据分析
ZPC821022 分钟前
如何将机械臂末端定位精度提升至微米如何进行标定
人工智能·算法·机器人
wabs66623 分钟前
关于动态规划【力扣343.整数拆分的递推公式怎么理解?】
算法·leetcode·动态规划
测试狗科研平台24 分钟前
第一性原理CO2还原反应计算流程和软件推荐
科技·算法·云计算
SEO_juper24 分钟前
2026 谷歌 SEO&GEO 常见问题合集:收录、排名、内容、技术全解析
算法·谷歌·常见问题·seo·跨境电商·外贸·geo
叫我:松哥36 分钟前
基于卷积神经网络的静态手势语识别算法,在测试集上的识别准确率达到97.5%
人工智能·python·深度学习·神经网络·算法·cnn
珊瑚里的鱼40 分钟前
【动态规划】买卖股票的最佳时机含手续费
算法·动态规划
2401_885665191 小时前
从零搭建卷积神经网络:基于PyTorch实现MNIST手写数字分类
pytorch·python·神经网络·算法·机器学习·分类·cnn