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

计算机有多难?

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

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

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

百度百科
百度百科

张锡峰曾就读于衡水中学,在 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,一经查实,立即删除!

相关文章

ViewModel、Lifecycles、LiveData基本使用

以下是使用Java实现ViewModel、Lifecycles和LiveData的基本用法&#xff0c;以及它们的原理简述。 ViewModel的基本使用&#xff08;Java&#xff09; 1. 引入依赖 在你的build.gradle文件中添加以下依赖&#xff1a; implementation androidx.lifecycle:lifecycle-viewmod…

MySQL查询性能优化解决方案

解决方案 主键与默认常用查询字段建立索引&#xff0c;普通字段类型选择 UNIQUE&#xff0c;索引方法 BTREE &#xff1b;长文本使用 FULLTEXT&#xff0c;索引方法为无&#xff1b; 新建表时引擎默认设置为 MyISAM&#xff0c;不使用 InnoDB&#xff0c;因为 MyISAM 支持 MAT…

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

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

拆分shp数据要素为多个shp

我有一个各县shp文件&#xff0c;我想要拆分成不同的要素&#xff0c;命名根据NAME字段进行命名&#xff0c;字段值是字符串&#xff0c;以下为基于arcpy的python实现代码。&#xff08;python2.7&#xff09; import arcpy import os# 设置工作空间和输入的 shapefile 文件路…

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 新服务器…

Webrtc支持FFMPEG硬解码之Intel(一)

前言 此系列文章分分为三篇, Webrtc支持FFMPEG硬解码之Intel(一)-CSDN博客 Webrtc支持FFMPEG硬解码之NVIDA(二)-CSDN博客 Webrtc支持FFMPEG硬解码之解码实现(三)-CSDN博客 AMD硬解目前还没找到可用解码器,欢迎留言交流 环境 Windows平台 VS20

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;方法改了又改&…

算法第9章 图算法设计

7-1 旅游规划 #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef pair<int,int> PII; const int N 510; int g[N][N]; int n,m,s,d; int dist[N]; int w[N],t[N][N]; bool st[N]; void dijkstra(){ memset…

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.汉字…

C++:列表初始化

文章目录 {}初始化std::initializer_listautodecltypenullptr {}初始化 在C98中&#xff0c;标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如&#xff1a; struct Point {int _x;int _y; };int main() {// 数组初始化int array1[] { 1, 2, 3, 4, 5…

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

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

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

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

03试验范式V1.1

对应视频链接点击直达 01项目点击下载&#xff0c;可直接运行&#xff08;含数据库&#xff09; 03试验范式V1.1 对应视频链接点击直达当前试验情况事件分类操作方案计时误差控制分析方案 遇到的主要问题--干扰很强--有时候还能直接假死硬件嵌入式解决方案唯二解决方案 结语其…

uniapp 仿写弹窗

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

JDBC连接HANA

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import com.sap.db.jdbc.Driver; public class HanaMultiTenantConnection {public static void main(String[] args) {// 数据库驱动类名String driver "com.sap.db.jdbc.Dr…

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

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