小红书(社招二面)算法原题

萝卜快跑涨价

距离我们上次谈 萝卜快跑 不足半月,萝卜快跑迎来了不少"反转"。

先是被曝远程后台有人操控,真实日成本超 400:

alt

最近还被不少网友吐槽:萝卜快跑涨价了,如今价格和网约车持平。

据不少博主实测,最近武汉萝卜快跑的打车成功率,低得离谱,不足 30%,基本上叫车 3~4 次,才能成功 1 次。

alt

叫车不好叫,价格还贵。

之前的萝卜快跑,叠加优惠等福利,可以做到几毛钱一公里,如今的价格基本上都在 1.5 元以上,和网约车基本持平。

知道「打车自由」迟早要没,但没想到没得这么快 🤣

首先,萝卜快跑的定价权是在百度手上的,萝卜快跑如今选择涨价,和网约车保持相当的水准。

我觉得和前段时间萝卜快跑的舆论热度超预期是密切相关的,而且在当前时间节点选择涨价到网约车水平,我觉得是非常聪明的。

先别急着反驳,我当然也是希望打车自由的时间能长一点。

但如果从百度(甚至是社会交通运输行业)的角度出发,萝卜快跑还是一个尚未全国铺开的产品,甚至还是一个内测产品,同时也代表了一个未来很有前景的行业,现如今却落入"抢人类饭碗"的社会问题舆论中,很容易就会导致整个行业被扼杀。

尤其是被曝日成本超过 400 之后,如果萝卜快跑再继续保持补贴低价,舆论只会更加汹涌。

从现在的环境分析,萝卜快跑的流量已经上来了,此时选择涨价到正常水平,可以进一步平衡订单的供求关系,又可以让舆论冷却,还能达成当时补贴是「为了拿到更多真实数据」的目的,是最符合经济原则的做法。

...

回归主题。

来一道和「小红书,社招二面」相关的算法原题。

题目描述

平台:LeetCode

题号:1206

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

跳表 是在 时间内完成增加、删除、搜索操作的数据结构。

跳表相比于树堆与红黑树,其功能与性能相当,并且跳表的代码长度相较下更短,其设计思想与链表相似。

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

alt

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

跳表的每一个操作的平均时间复杂度是 ,空间复杂度是 。

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

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

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

示例 1:

输入
["Skiplist""add""add""add""search""add""search""erase""erase""search"]
[[], [1], [2], [3], [0], [4], [1], [0], [1], [1]]

输出
[null, null, null, null, false, null, truefalsetruefalse]

解释
Skiplist skiplist = new Skiplist();
skiplist.add(1);
skiplist.add(2);
skiplist.add(3);
skiplist.search(0);   // 返回 false
skiplist.add(4);
skiplist.search(1);   // 返回 true
skiplist.erase(0);    // 返回 false,0 不在跳表中
skiplist.erase(1);    // 返回 true
skiplist.search(1);   // 返回 false,1 已被擦除

提示:

  • 调用 search, add,   erase 操作次数不大于 

数据结构

对于单链表而言,所有的操作(增删改查)都遵循「先查找,再操作」的步骤,这导致在单链表上所有操作复杂度均为 (瓶颈在于查找过程)。

跳表相对于单链表,则是通过引入「多层」链表来优化查找过程,其中每层链表均是「有序」链表:

  • 对于单链表的 Node 设计而言,我们只需存储对应的节点值 val,以及当前节点的下一节点的指针 ne 即可(ne 为一指针变量)

  • 对于跳表来说,除了存储对应的节点值 val 以外,我们需要存储当前节点在「每一层」的下一节点指针 nene 为指针数组)

跳表的 level 编号从下往上递增,最下层的链表为元素最全的有序单链表,而查找过程则是按照 level 从上往下进行。

alt

操作次数的数据范围为 ,因此设计最大的 level 为 即可确保复杂度,但由于操作次数 不可能全是 add 操作,因此这里直接取 level 为 10。

同时为了简化,建立一个哨兵节点 he,哨兵值的值应当足够小(根据数据范围,设定为 即可),所有的操作(假设当前操作的传入值为 t),先进行统一化的查找:「查找出每一层比 t 严格小的最后一个节点,将其存成 ns 数组。即 为 层严格比 小的最后一个节点。」

再根据不同的操作进行下一步动作:

  • search 操作:由于最后一层必然是元素最全的单链表,因此可以直接访问 ns[0].ne[0] 即是所有元素中满足大于等于 t 的第一个元素,通过判断其值与传入值 t 的大小关系来决定结果;
  • add 操作:由于最后一层必然是元素最全的单链表,因此我们「从下往上」进行插入,最底下一层必然要插入,然后以一半的概率往上传递;
  • erase 操作:与 add 操作互逆,按照「从下往上」的顺序进行删除。需要注意的是,由于相同的值在跳表中可能存在多个,因此我们在「从下往上」删除过程中需要判断待删除的元素与 ns[0].ne[0] 是否为同一元素(即要判断地址是否相同,而不是值相同)。

Java 代码:

class Skiplist {
    int level = 10;
    class Node {
        int val;
        Node[] ne = new Node[level];
        Node (int _val) {
            val = _val;
        }
    }
    Random random = new Random();
    Node he = new Node(-1);
    void find(int t, Node[] ns) {
        Node cur = he;
        for (int i = level - 1; i >= 0; i--) {
            while (cur.ne[i] != null && cur.ne[i].val < t) cur = cur.ne[i];
            ns[i] = cur;
        }
    }
    public boolean search(int t) {
        Node[] ns = new Node[level];
        find(t, ns);
        return ns[0].ne[0] != null && ns[0].ne[0].val == t;
    }
    public void add(int t) {
        Node[] ns = new Node[level];
        find(t, ns);
        Node node = new Node(t);
        for (int i = 0; i < level; i++) {
            node.ne[i] = ns[i].ne[i];
            ns[i].ne[i] = node;
            if (random.nextInt(2) == 0break;
        }
    }
    public boolean erase(int t) {
        Node[] ns = new Node[level];
        find(t, ns);
        Node node = ns[0].ne[0];
        if (node == null || node.val != t) return false;
        for (int i = 0; i < level && ns[i].ne[i] == node; i++) ns[i].ne[i] = ns[i].ne[i].ne[i];
        return true;
    }
}

Python 代码:

class Skiplist:
    def __init__(self, level=10):
        self.level = level
        class Node:
            def __init__(self, val):
                self.val = val
                self.ne = [None] * level
        self.Node = Node
        self.he = Node(-1)

    def find(self, t, ns):
        cur = self.he
        for i in range(self.level - 1-1-1):
            while cur.ne[i] is not None and cur.ne[i].val < t:
                cur = cur.ne[i]
            ns[i] = cur

    def search(self, t):
        ns = [None] * self.level
        self.find(t, ns)
        return ns[0].ne[0is not None and ns[0].ne[0].val == t

    def add(self, t):
        ns = [None] * self.level
        self.find(t, ns)
        node = self.Node(t)
        for i in range(self.level):
            node.ne[i] = ns[i].ne[i]
            ns[i].ne[i] = node
            if random.randint(01) == 0:
                break

    def erase(self, t):
        ns = [None] * self.level
        self.find(t, ns)
        node = ns[0].ne[0]
        if node is None or node.val != t:
            return False
        for i in range(self.level):
            if ns[i].ne[i] == node:
                ns[i].ne[i] = ns[i].ne[i].ne[i]
        return True

TypeScript 代码:

const level: number = 10
class TNode {
    val: number
    ne: TNode[] = new Array<TNode>(level)
    constructor(_val: number) {
        this.val = _val
    } 
}
class Skiplist {
    he: TNode = new TNode(-1)
    find(t: number, ns: TNode[]): void {
        let cur = this.he
        for (let i = level - 1; i >= 0; i--) {
            while (cur.ne[i] != null && cur.ne[i].val < t) cur = cur.ne[i]
            ns[i] = cur
        }
    }
    search(t: number): boolean {
        let ns: TNode[] = new Array<TNode>(level)
        this.find(t, ns)
        return ns[0].ne[0] != null && ns[0].ne[0].val == t
    }
    add(t: number): void {
        let ns: TNode[] = new Array<TNode>(level)
        this.find(t, ns)
        const node = new TNode(t)
        for (let i = 0; i < level; i++) {
            node.ne[i] = ns[i].ne[i]
            ns[i].ne[i] = node
            if (Math.round(Math.random()) == 0break
        }
    }
    erase(t: number): boolean {
        let ns: TNode[] = new Array<TNode>(level)
        this.find(t, ns)
        const node = ns[0].ne[0]
        if (node == null || node.val != t) return false
        for (let i = 0; i < level && ns[i].ne[i] == node; i++) ns[i].ne[i] = ns[i].ne[i].ne[i]
        return true
    }
}
  • 时间复杂度:所有操作的复杂度瓶颈在于 find 查找, find 查找期望复杂度为
  • 空间复杂度:

最后

巨划算的 LeetCode 会员优惠通道目前仍可用 ~

使用福利优惠通道 leetcode.cn/premium/?promoChannel=acoier,年度会员 有效期额外增加两个月,季度会员 有效期额外增加两周,更有超大额专属 🧧 和实物 🎁 福利每月发放。

我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻

欢迎关注,明天见。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

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

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

相关文章

17 Python常用内置函数——基本输入输出

input() 和 print() 是 Python 的基本输入输出函数&#xff0c;前者用来接收用户的键盘输入&#xff0c;后者用来把数据以指定的格式输出到标准控制台或指定的文件对象。无论用户输入什么内容&#xff0c;input() 一律作为字符串对待&#xff0c;必要时可以使用内置函数 int()、…

【SpringBoot教程:从入门到精通】掌握Springboot开发技巧和窍门(四)-Vue项目配置环境、导航栏

主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; 文章目录 前言 Vue项目配置环境 安装依赖 创建菜单 总结 前言 主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; Vue项目配置环境 安装…

【算法】分布式共识Paxos

一、引言 在分布式系统中&#xff0c;一致性是至关重要的一个问题。Paxos算法是由莱斯利兰伯特&#xff08;Leslie Lamport&#xff09;在1990年提出的一种解决分布式系统中一致性问题的算法。 二、算法原理 Paxos算法的目标是让一个分布式系统中的多个节点就某个值达成一致。算…

2000-2023年上市公司全要素生产率数据LP法(含原始数据+计算代码+结果)

2000-2023年上市公司全要素生产率数据LP法&#xff08;含原始数据计算代码结果&#xff09; 1、时间&#xff1a;2000-2023年 2、指标&#xff1a;stkcd、year、证券代码、固定资产净额、资产总计、负债合计、支付给职工以及为职工支付的现金、购建固定资产无形资产和其他长期…

Monaco 使用 LinkedEditingRangeProvider

Monaco LinkEdit 功能是指同时修改同样的字符串&#xff0c;例如在编辑 Html 时&#xff0c;修改开始标签时会同时修改闭合标签。Monaco 支持自定义需要一起更新的字符串列表。最终效果如下&#xff1a; 首先&#xff0c;通过 registerLinkedEditingRangeProvider 注册 LinkEd…

关键词查找【Knuth-Morris-Pratt (KMP) 算法】

一个视频让你彻底学懂KMP算法_哔哩哔哩_bilibili KMP算法的核心是利用匹配失败后的信息&#xff0c;尽量减少模式串与主串的匹配次数以达到快速匹配的目的。 第一步&#xff1a;计算模式串(子串)和next[j]数组 模式串 前2位字母的next[j]固定是0 和 1 后续字母的nex[j]&…

生成式AI的发展方向是chat还是Agent探讨

生成式 AI 的发展方向&#xff0c;是 Chat 还是 Agent&#xff1f; 随着生成式AI技术的不断进步&#xff0c;关于其未来发展方向的讨论也愈发激烈。究竟生成式AI的未来是在对话系统&#xff08;Chat&#xff09;中展现智慧&#xff0c;还是在自主代理&#xff08;Agent&#x…

MySQL之触发器和存储过程

1、触发器 触发器简介 触发器&#xff08;trigger&#xff09;是一个特殊的存储过程&#xff0c;它的执行不是由程序调用&#xff0c;也不是手工启动&#xff0c;而是由事件来触 发&#xff0c;比如当对一个表进行操作&#xff08; insert&#xff0c;delete&#xff0c; upda…

js返回一个月的所有天数,用数组表示

直接上代码 import dayjs from dayjs import isSameOrBefore from dayjs/plugin/isSameOrBefore dayjs.extend(isSameOrBefore)function getCurrentMonthDays(month) {const firstDay dayjs().startOf(month);const lastDay dayjs().endOf(month);const allDatesInMonth []…

【C++笔试强训】day05

游游的you 思路 贪心&#xff1a;优先组成 you&#xff0c;最少的字母决定了you的数量。需要注意&#xff1a;如果oo剩下n个&#xff0c;那么相邻oo的个数是n-1个&#xff0c;而不是n/2个。 例如 oooooo oo oo oooo oo 6个o&#xff0c;两两组合有3对&#xff0c;掐头去尾有…

【支持语言模型和视觉语言模型的推理引擎sglang】

介绍 sglang是一个AI推理引擎&#xff0c;是一个专门为大语言模型和视觉语言模型设计的高效服务框架。 就像F1赛车需要顶级发动机一样&#xff0c;大语言模型也需要高效的推理引擎来发挥潜力。 而sglang正是这样一个性能怪兽。 根据LMSys组织的官方公告&#xff0c;最新的s…

CCS(Code Composer Studio 10.4.0)编译软件中文乱码怎么解决

如果是所有文件都出现了中文乱码这时建议直接在窗口首选项中修改&#xff1a;选择"Window" -> "Preferences"&#xff0c;找到"General" -> "Workspace"&#xff0c;将"Text file encoding"选项设置为"Other&quo…

Mac printf处理参数的奇特之处(macOS中,printf使用%d输出一个浮点数会发生什么情况?)

今天早上网上冲浪的时候看到了 2016 年的一篇文章&#xff0c;里面提到了一段代码&#xff1a; #include <stdio.h> int main() {double a 10;printf("a %d\n", a);return 0; }说这段代码在 x86&#xff08;IA-32&#xff09;上运行时&#xff0c;输出为0&a…

Java语言程序设计——篇八(1)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; Java常用核心类 主要内容Object: 终极父类toString( )方法equals( )方法getClass( )方法hashCode( )方法clone( )方法finalize( )方法实战演练 …

c语言之给三个数字排大小

写代码将三个整数数按从大到小输出。 例如&#xff1a; 输入&#xff1a;2 3 1 输出&#xff1a;3 2 1 首先三个整数从大到小排&#xff0c;先创建三个变量 输入数字大小 通过冒泡排序派大小最后在输出出来。 简单介绍一下冒泡排序&#xff0c;后期在完整的写出来 冒泡排…

文件上传总结

一、原理 通过界面上的上传功能上传了一个可执行的脚本文件&#xff0c;而WEB端的系统并未对其进行检测或者检测的逻辑做的不够好&#xff0c;使得恶意用户可以通过文件中上传的一句话木马获得操控权 二、绕过方法 1>前端绕过 1.删除前端校验函数 checkFile() 2.禁用js…

华为Ascend C算子开发(中级)考试

华为Ascend C算子开发&#xff08;中级&#xff09;考试题 提示&#xff1a;这个是河北廊坊Ascend C算子开发考试题和答案&#xff0c;仅供参考&#xff0c;因为不确定其他城市的考试题是否也是一样 文章目录 华为Ascend C算子开发&#xff08;中级&#xff09;考试题一、op_ho…

捉虫笔记(1)之 WinDbg符号配置

WinDbg符号配置 1、WinDbg简单介绍 WinDbg 是微软的一款强大的调试工具&#xff0c;用于 Windows 平台的内核和用户模式调试。它提供了一系列强大的功能&#xff0c;包括内存和寄存器的查看、断点设置、堆栈跟踪、性能分析等。 WinDbg 的历史可以追溯到微软早期的调试工具&a…

最新风车IM即时聊天源码及完整视频教程2024年7月版

堡塔面板 试验性Centos/Ubuntu/Debian安装命令 独立运行环境&#xff08;py3.7&#xff09; 可能存在少量兼容性问题 不断优化中 curl -sSO http://io.bt.sy/install/install_panel.sh && bash install_panel.sh 1.宝塔环境如下: Nginx 1.20 Tomcat 8 MySQL 8.0 R…

从0到1搭建一个组件库

最近我开启了一个新项目&#xff0c;基于echarts进行二次封装&#xff0c;希望能为Vue3项目量身打造一套高效、易用的图表组件库&#xff0c;取名为 v-echarts。 目前雏形已经搭建完成&#xff0c;先把整个搭建过程做一个记录。后续再持续迭代、完善该图表组件库。 v-echarts 文…