看完“土猪拱白菜“的张锡峰,我明白计算机有多难了

计算机有多难?

今天无意中,看到一篇关于「"土猪拱白菜"学霸后悔报考浙大计算机」的文章。

或许会有不少和我刚开始一样懵圈的同学:张锡峰是谁?"土猪拱白菜"又是什么梗?

带着疑惑,我打开了简中网著名的搜索引擎,找到这位曾经少年的大三在读生的故事。

百度百科
百度百科

张锡峰曾就读于衡水中学,在 2021 年,作为高三学生的他参加综艺节目《超级演说家》,因演讲内容「我就是一只来自乡下的"土猪",也要立志,去拱了大城市里的白菜」而出圈。

当时这句话被病毒式传播。

这场演讲也被普遍解读为:不屈不挠、勇于奋斗。尽管来自小地方,但有着进入大城市、实现自己梦想的决心。

有流量的地方就有对立,除了得到了大多数人的共鸣认可以外,也有不少质疑张锡峰的声音。

面对这些声音,张锡峰除了强势回应「你以为我们每天天不亮就奔向操场,一边奔跑一边呼喊是为了什么?是假装吗?是作秀吗?我们是为了改命啊!」以外,「还以 674 分的高考成绩考入浙大计算机」

如果故事只是到这里结束,那很好,一个眼里有光的少年,面对质疑打破质疑,成就自我。

但时间很快,张锡峰现在是一名大三学生,也要考虑实习找工作的事儿,也要面临这日趋严峻的就业环境。

遗憾的是,重现在网友面前的张锡峰,从「阳光、活力、干翻一切」变成「平静、冷漠、眼里没光」。

alt
alt

这让我想起来之前在公众号的网友留言,原话我不太记得了,大致意思是:当时报计算机专业,真觉得挺好,薪资也高,但随着找不到工作,以及参与工作之后的 996,也分不清楚自己是不是真的喜欢这行了。

这些话题看多了,聊多了,我开始理解,有些兴趣爱好甚至是热爱,之所以还在,可能真就被生活放了一马罢了。

让我感到绝望的是,代表希望的种子被击落之后,不少人开始反过来攻击种子本身。

最近网上出现了另一种质疑声音:会不会这个张锡峰就是个普通的"小镇做题家",只是那场演讲把他捧到了天上。

但只要继续深究就不难发现,早在那场演讲之前,张锡峰就以「励志、干翻一切」小有名气。

2019 年,他在衡水中学的演讲《这世间,唯有青春与梦想不可辜负》在 B 站就有 2300W+ 的播放量。

alt

所以,是他的励志使他站上了《超级演说家》的舞台,而不是刚好被综艺的风吹起。

校园世界和现实世界,是两个世界,这没错。

但不代表我们不需要张锡峰这样的孩子,不需要这种向往。

张锡峰只是在他那个年纪做了大多数人都想做的事情,他或许失败了,但不该被嘲讽,不该成为乐子。

就像哥谭不该只有蝙蝠侠一样。

...

回归主线。

来一道和「华为」相关的题目。

题目描述

平台:LeetCode

题号:1032

设计一个算法:接收一个字符流,并检查这些字符的后缀是否是字符串数组 words 中的一个字符串。

例如,words = ["abc", "xyz"] 且字符流中逐个依次加入 个字符 'a''x''y''z' ,你所设计的算法应当可以检测到 "axyz" 的后缀 "xyz" 与 words 中的字符串 "xyz" 匹配。

按下述要求实现 StreamChecker 类:

  • StreamChecker(String[] words) :构造函数,用字符串数组  words 初始化数据结构。
  • boolean query(char letter):从字符流中接收一个新字符,如果字符流中的任一非空后缀能匹配 words 中的某一字符串,返回 true;否则,返回 false

示例:

输入:
["StreamChecker""query""query""query""query""query""query""query""query""query""query""query""query"]
[[["cd""f""kl"]], ["a"], ["b"], ["c"], ["d"], ["e"], ["f"], ["g"], ["h"], ["i"], ["j"], ["k"], ["l"]]

输出:
[null, falsefalsefalsetruefalsetruefalsefalsefalsefalsefalsetrue]

解释:
StreamChecker streamChecker = new StreamChecker(["cd""f""kl"]);
streamChecker.query("a"); // 返回 False
streamChecker.query("b"); // 返回 False
streamChecker.query("c"); // 返回n False
streamChecker.query("d"); // 返回 True ,因为 'cd' 在 words 中
streamChecker.query("e"); // 返回 False
streamChecker.query("f"); // 返回 True ,因为 'f' 在 words 中
streamChecker.query("g"); // 返回 False
streamChecker.query("h"); // 返回 False
streamChecker.query("i"); // 返回 False
streamChecker.query("j"); // 返回 False
streamChecker.query("k"); // 返回 False
streamChecker.query("l"); // 返回 True ,因为 'kl' 在 words 中

提示:

  • words[i] 由小写英文字母组成
  • letter 是一个小写英文字母
  • 最多调用查询

Trie + 枚举

先考虑最为简单的做法:将给定的所有 顺序插入字典树,根据数据范围可知这一步计算量为 ,其中最大的 长度只有 200。

然后利用 长度只有 200 这一条件,直接使用「枚举」的方式来实现 query

具体的,我们可以先使用一个字符串 s 来记录 query 操作产生的数据流,然后实现一个 boolean query(int start, int end) 方法,该方法会检查字典树中是否存在 子串。

由于 长度只有 200(假设当前 s 的长度为 n),因此我们只需要枚举「 作为子串左端点, 作为子串右端点」是否存在字典树中(是否存在 中)即可,最坏情况下,单次 query 操作计算量为

一些细节:为了避免每个样例都 new 大数组,我们可以使用 static 优化。

Java 代码:

class StreamChecker {
    static int N = 2010 * 200, idx = 0;
    static int[][] tr = new int[N][26];
    static boolean[] isEnd = new boolean[N * 26];
    StringBuilder sb = new StringBuilder();
    void add(String s) {
        int p = 0;
        for (int i = 0; i < s.length(); i++) {
            int u = s.charAt(i) - 'a';
            if (tr[p][u] == 0) tr[p][u] = ++idx;
            p = tr[p][u];
        }
        isEnd[p] = true;
    }
    boolean query(int start, int end) {
        int p = 0;
        for (int i = start; i <= end; i++) {
            int u = sb.charAt(i) - 'a';
            if (tr[p][u] == 0return false;
            p = tr[p][u];
        }
        return isEnd[p];
    }
    public StreamChecker(String[] words) {
        for (int i = 0; i <= idx; i++) {
            Arrays.fill(tr[i], 0);
            isEnd[i] = false;
        }
        idx = 0;
        for (String s : words) add(s);
    }
    public boolean query(char c) {
        sb.append(c);
        int n = sb.length(), min = Math.max(0, n - 200);
        for (int i = n - 1; i >= min; i--) {
            if (query(i, n - 1)) return true;
        }
        return false;
    }
}

C++ 代码:

class StreamChecker {
public:
    static const int N = 2010 * 200;
    int tr[N][26];
    bool isEnd[N];
    string sb;
    int idx = 0;
    void add(const string &s) {
        int p = 0;
        for (char c : s) {
            int u = c - 'a';
            if (tr[p][u] == 0) tr[p][u] = ++idx;
            p = tr[p][u];
        }
        isEnd[p] = true;
    }
    bool query(int start, int end) {
        int p = 0;
        for (int i = start; i <= end; i++) {
            int u = sb[i] - 'a';
            if (tr[p][u] == 0return false;
            p = tr[p][u];
        }
        return isEnd[p];
    }
    StreamChecker(const vector<string>& words) {
        memset(tr, 0sizeof(tr));
        memset(isEnd, 0sizeof(isEnd));
        for (const string &s : words) add(s);
    }
    bool query(char c) {
        sb.push_back(c);
        int n = sb.length(), min = max(0, n - 200);
        for (int i = n - 1; i >= min; i--) {
            if (query(i, n - 1)) return true;
        }
        return false;
    }
};
  • 时间复杂度: StreamChecker 初始化复杂度为 ,其中 words 字符总数; query 操作复杂度为 ,其中 为最大 words[i] 长度
  • 空间复杂度: ,其中 words 字符总数, 为字符集大小

Trie(优化)

初始化将所有的 存入 Trie 是必然的,我们只能考虑如何优化 query 操作。

在解法一中,我们需要对新数据流对应的字符串的每个后缀进行搜索,同时每次搜索是相互独立的,即本次匹配不会对下一次匹配产生贡献。

「实际上,我们可以通过「倒序建 Trie」的方式,将「枚举检查多个后缀」的操作变为「匹配一次后缀」操作。」

具体的,我们可以在初始化 StreamChecker 时,将每个 翻转(倒序)加入 Trie 中;然后在 query 操作时(假设当前数据流对应的字符串为 s,长度为 n),从 s 的尾部开始在 Trie 中进行检索(即从 开始往回找)。

若在某个位置 idx 时匹配成功,意味着 的翻转子串在字典树中,同时我们又是将每个 words[i] 进行倒序插入,即意味着 的正向子串在 words 中,即满足 s 的某个后缀出现在 words 中。

同理,我们可以利用最大的 words[i] 长度为 200 来控制从 开始往回找的最远距离,同时利用当某个短后缀不在 Trie 中,则其余长度更大的后缀必然不在 Trie 中进行剪枝操作。

Java 代码:

class StreamChecker {
    static int N = 2010 * 200, idx = 0;
    static int[][] tr = new int[N][26];
    static boolean[] isEnd = new boolean[N * 26];
    StringBuilder sb = new StringBuilder();
    void add(String s) {
        int p = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            int u = s.charAt(i) - 'a';
            if (tr[p][u] == 0) tr[p][u] = ++idx;
            p = tr[p][u];
        }
        isEnd[p] = true;
    }
    public StreamChecker(String[] words) {
        for (int i = 0; i <= idx; i++) {
            Arrays.fill(tr[i], 0);
            isEnd[i] = false;
        }
        idx = 0;
        for (String s : words) add(s);
    }
    public boolean query(char c) {
        sb.append(c);
        int n = sb.length(), min = Math.max(0, n - 200), p = 0;
        for (int i = n - 1; i >= min; i--) {
            if (isEnd[p]) return true;
            int u = sb.charAt(i) - 'a';
            if (tr[p][u] == 0return false;
            p = tr[p][u];
        }
        return isEnd[p];
    }
}

C++ 代码:

class StreamChecker {
public:
    static const int N = 2010 * 200;
    static const int ALPHABET_SIZE = 26;
    vector<vector<int>> tr;
    vector<bool> isEnd;
    string sb;
    int idx = 0;
    void add(const string &s) {
        int p = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            int u = s[i] - 'a';
            if (tr[p].size() <= u) tr[p].resize(u + 10);
            if (tr[p][u] == 0) tr[p][u] = ++idx;
            p = tr[p][u];
        }
        isEnd[p] = true;
    }
    StreamChecker(const vector<string>& words) {
        tr.resize(N);
        isEnd.resize(N);
        fill(isEnd.begin(), isEnd.end(), false);
        for (const auto &s : words) {
            add(s);
        }
    }
    bool query(char c) {
        sb.push_back(c);
        int n = sb.length(), min = max(0, n - 200), p = 0;
        for (int i = n - 1; i >= min; i--) {
            if (isEnd[p]) return true;
            int u = sb[i] - 'a';
            if (tr[p].size() <= u || tr[p][u] == 0return false;
            p = tr[p][u];
        }
        return isEnd[p];
    }
};
  • 时间复杂度: StreamChecker 初始化复杂度为 ,其中 words 字符总数; query 操作复杂度为 ,其中 为最大 words[i] 长度
  • 空间复杂度: ,其中 words 字符总数, 为字符集大小

最后

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

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

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

欢迎关注,明天见。

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

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

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

相关文章

Tita 360评估:有效 360度反馈流程的 10 大步骤

宣传过程 如果你的公司首次引入多方位反馈或 360 度反馈&#xff0c;那么向所有利益相关者描述这一流程至关重要。由于流程太新&#xff0c;很多人还不了解。确保参与该流程的每个人都了解其目的&#xff0c;以及将如何实施该流程和使用其结果。花时间在一对一会议、小组会议和…

python的a[:2]、a[:] 和a [::] 的区别

一、a[:2] 数据准备 import numpy as np X np.array([[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13],[14,15],[16,17],[18,19]]) print(X)形成矩阵 print (“X[: 2]:”, X[: 2]) ### :表示索引 0至1行&#xff1b; 二、a[:]和a [::] 在 Python 中&#xff0c;[:] 和 [::…

SQL Server 安装后,服务器再改名,造成名称不一致,查询并修改数据库服务器真实名称

SELECT SERVERNAME -- 1.查询旧服务器名称 SELECT serverproperty(servername) AS new --2.查询新服务器名称 -- 3.更新服务器名称 IF SERVERPROPERTY(servername) <> 新服务器名称替换 BEGIN DECLARE server_name NVARCHAR(128) SET server_name 新服务器…

Linux部署项目

手动部署 1.在IDEA写一个有关springboot项目 在windows客户端可以通过localhost:8080/hello 访问 2.用packge 命令将该springboot项目打包 并在target目录下找到打包的jar包 3.上传到linux上 个人习惯在usr/local/app 下上传该项目 创建切换到app目录下 mkdir /usr/local/ap…

无文件落地分离拆分-将shellcode从文本中提取-file

马子分为shellcode和执行代码. --将shellcode单独拿出,放在txt中---等待被读取执行 1-cs生成python的payload. 2-将shellcode进行base64编码 import base64code b en_code base64.b64encode(code) print(en_code) 3-将编码后的shellcode放入文件内 4-读取shellcod…

记录pytest中场景执行的token异常处理问题

前言中写了一个conftest钩子函数用于处理重复调用token的方法&#xff0c;http://t.csdnimg.cn/N4rCK&#xff0c;每个用例单独执行都很正常&#xff0c;但是批量执行时一直报错&#xff0c;token缓存处理也不生效。 所有的用例都报获取不到token&#xff0c;方法改了又改&…

C++和C语言到底有什么区别?

引言&#xff1a;C和C语言是两种非常常见的编程语言&#xff0c;由于其广泛的应用和灵活性&#xff0c;它们在计算机科学领域内受到了广泛的关注。虽然C是从C语言发展而来的&#xff0c;但是这两种语言在许多方面都有所不同。本文将对C和C语言进行比较和分析&#xff0c;以便更…

Modbus通信协议(1)--基础知识

一、基础知识 1.信息的划分 2.基本概念 3.机器数和真值 4.原码、反码与补码 5.存储单位 6.基本类型数据 7.数的浮点表示 8.各种进位制的对比 9.十进制 10.二进制 11.十六进制 12.不同进制的换算 13.位的标记 二、常用的信息编码 1.西文字符的计算机表示 2.汉字处理过程 3.汉字…

如何用ai写文案?分享方法和软件!

在当今数字化时代&#xff0c;内容创作已经成为各行各业不可或缺的一部分。然而&#xff0c;对于许多创作者来说&#xff0c;如何写出既具有吸引力又符合平台特点的文案&#xff0c;却是一项不小的挑战。幸运的是&#xff0c;人工智能&#xff08;AI&#xff09;技术的快速发展…

解决使用elmessage 没有样式的问题

错误情况 这里使用了一个消息提示&#xff0c;但是没有出现正确的样式&#xff0c; 错误原因和解决方法 出现这种情况是因为&#xff0c;在全局使用了按需导入&#xff0c;而又在局部组件中导入了ElMessage组件&#xff0c;我们只需要将局部组件的import删除就可以了 import…

uniapp 仿写弹窗

页面 <template><view click"close" class"mask"><view click.stop"onClick" class"content"><text class"text">点击蒙层关闭</text></view></view> </template><scr…

江协科技51单片机学习-0 购买套件

前言&#xff1a; 本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记&#xff0c;在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。 引用&#xff1a; 51单片机入门教程-2…

Blender雕刻建模_UV展开

UV展开的标准&#xff1a;展平&#xff0c;不重叠&#xff0c;均匀展开 ZenUV插件 切到边模式 -Mark&#xff0c;标记缝合边 -Unmark&#xff0c;取消标记 -Unmark All&#xff0c;全部取消标记 -Mirror Seams&#xff0c;镜像缝合边 -Zen Unwrap&#xff0c;全部展开 纹…

web端使用高德地图

web端使用高德地图 一、申请高德key和秘钥二、在项目中引入所需功能js、css文件三、实现地图选点、回显选点四、自定义地图 一、申请高德key和秘钥 申请高德key 申请成功后可以得到key 二、在项目中引入所需功能js、css文件 <script src"https://webapi.amap.com/m…

node调试

vscode安装插件&#xff1a;JavaScript Debugger (Nightly) 点击后生成一个launch.json文件 打断点&#xff0c;并发送一个请求来执行代码到断点处 按右上的向下箭头&#xff0c;进入源码&#xff0c;进行查看&#xff0c;左边查看变量等值

IDEA创建简单web(servlet)项目(server为tomcat)

引言 鉴于网上很少有关于IDEA开发servlet项目的教程&#xff08;24版idea&#xff0c;并且servlet技术十分复古&#xff0c;很少有人用到&#xff0c;能够理解&#xff0c;该文章旨在为在校的学生提供一个参考&#xff0c;项目技术简单&#xff09;本人在此总结从头开始到项目…

哪个牌子的儿童护眼灯好?五款平价护眼台灯推荐

护眼台灯在近年来成为家长和长时间使用电子设备人群关注的家电/学生产品。对于家中有孩子或经常面对电子屏幕的人士来说&#xff0c;很多人可能已经对这类产品有所了解并进行了购买。然而&#xff0c;部分家长对护眼台灯的认识还不够深入&#xff0c;因此尚未为孩子选择一款合适…

无公网IP与服务器完成企业微信网页应用开发远程调试详细流程

文章目录 前言1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 前言 本文主要介绍如何在企业微信开发者中心通过使用内网穿透工具提供的公网域名成功验证回调本地接口服务! …

postman教程-21-Newman运行集合生成测试报告

上一小节我们Postman Newman的安装方法&#xff0c;本小节我们讲解一下Postman Newman的具体使用方法。 使用Newman运行集合 1、导出Postman集合&#xff1a; 在Postman中&#xff0c;选择你想要运行的集合&#xff0c;然后点击“导出”按钮&#xff0c;选择导出为“Collect…

【CS.PL】Lua 编程之道: 控制结构 - 进度24%

3 初级阶段 —— 控制结构 文章目录 3 初级阶段 —— 控制结构3.1 条件语句&#xff1a;if、else、elseif3.2 循环语句&#xff1a;for、while、repeat-until3.2.1 输出所有的命令行参数3.2.2 while.lua3.2.3 repeat.lua及其作用域 &#x1f525;3.2.4 for.lua (For Statement)…