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

计算机有多难?

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

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

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

百度百科
百度百科

张锡峰曾就读于衡水中学,在 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,年度会员 有效期额外增加两个月,季度会员 有效期额外增加两周,更有超大额专属 🧧 和实物 🎁 福利每月发放。

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

欢迎关注,明天见。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型高考数学测评结果,国内AI大模型成绩超GPT-4o!

每年高考都是备受全社会关注的一件大事&#xff0c;而今年略有不同&#xff0c;因为除了鱼跃龙门的高三学子们&#xff0c;还多了许多陪他们一同参加考试的 AI 大模型。 在所有的考试科目中&#xff0c;数学显然一直都是最难的那一门&#xff0c;不论是对考生还是对大模型。因…

管理敏感数据

敏感数据泄露是指意外或故意泄露关键信息&#xff0c;例如个人身份信息&#xff08;PII&#xff09;、支付卡信息&#xff08;PCI&#xff09;、受保护的电子健康信息&#xff08;ePHI&#xff09;和知识产权&#xff08;IP&#xff09;&#xff0c;数据保护措施不足的组织会在…

2024 Java 异常—面试常见问题

目录 一、异常的分类 二、throw和throws都是异常处理的关键字&#xff0c;二者区别。 三、try-catch-finally 中&#xff0c;如果 catch 中 return 了&#xff0c;finally 还会执行吗&#xff1f; 四、try-catch-finally 中哪个部分可以省略&#xff1f; 五、常见的 Runti…

neo4j-官网学习

1、cypher 代码学习文档 https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise 2、APOC函数包安装&#xff08;desktop&#xff09; 直接点击就可以安装&#xff0c;安装完之后重启一下&#xff0c;Cypher查询中使用CALL apoc.help(‘apoc’)来检查APOC插件是否已…

全网自动观影一条龙!一步到位的极空间nas-tools搭建教程

全网自动观影一条龙&#xff01;一步到位的极空间nas-tools搭建教程 哈喽小伙伴们好&#xff0c;我是Stark-C~&#xff0c;前几天为大家分享的《极空间全自动小雅Alist以及Emby全家桶部署教程》大家都反映没用上极空间自己强大的“极影视”有点可惜&#xff0c;所以今天再教大…

JasperReport-合并单元格

合并单元格是做报表时经常会遇到的需求。下面列举两种合并单元格的方式。 一、示例一 合并单元格在Subject。 1.1 创建5列的表 1.2 合并Column4和 Column5 按住Ctrl键点击Column4和 Column5,同时选中。然后右键,选择“Group Columns”。 1.3 合并成功 二、示例二 示例一…

VirtualBox 虚拟机中的 centos7 系统拉取 docker 镜像常见报错及解决方法

一、拉取镜像时报错&#xff1a;Error response from daemon: Get "https://registry-1.docker.io/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority 原因&#xff1a;&#xff08;文心一言给出的原因&#xff09; 这个错误…

产品经理研读:Agent的九种设计模式(图解+代码)

引言 上周五我在一个特工宇宙的社群里做了一次分享&#xff0c;题目是《从 YC 项目看 AI 趋势以及 AI agent 开发工具类产品该如何设计》&#xff0c;收到了大家不错的反馈&#xff0c;不过回看视频后还是发现不少可以提升的地方&#xff0c;感兴趣的朋友公众号回复“分享”获…

了解AIGC:让AI创造内容,改变未来

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 什么是AIGC&#xff1f; 定义和概念 &#x1f9e0; 关键技术 &#x1f916; AIGC的发展历程 &#x1f…

android studio过滤日志

荣耀手机的日志有很多乱七八糟的输出 在logcat设置过滤 filter name:过滤名称随意 log tag不知道是什么 log message设置过滤的内容或者设置显示的内容 需要过滤的内容&#xff1a; ^(?!.*(gralloc4|InputMethodManager|tagSocket|dataspace)).*$以|分割要过滤的内容 要显…

基于51单片机8x8点阵设计

基于51单片机8x8点阵设计 &#xff08;仿真&#xff0b;程序&#xff09; 功能介绍 具体功能&#xff1a; 1.用74HC138驱动8x8点阵&#xff1b; 2.按键可以切换模式&#xff1b; 3.一共4种模式&#xff0c;0~9数字闪出、动态爱心、坦克走动、数字依次向上平移&#xff1b; …

[天翼杯 2021]esay_eval

[天翼杯 2021]esay_eval <?php class A{public $code "";function __call($method,$args){eval($this->code);}function __wakeup(){$this->code "";} }class B{function __destruct(){echo $this->a->a();} } if(isset($_REQUEST[poc]…

减治法思想-二分查找图解案例

减治法介绍 减治法思想 ​ 分治法是将一个大问题划分为若干个子问题&#xff0c;分别求各个子问题&#xff0c;然后把子问题的解进行合并得到原问题的解。 ​ 减治法同样是把一个大问题划分为若干个子问题&#xff0c;但是并不是求解所有的子问题&#xff0c;因为原问题的解…

182.二叉树:二叉搜索树的最小绝对差(力扣)

代码解决 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* Tre…

剧本新纪元:探索短剧系统的魔力

在现代社会&#xff0c;随着科技的迅猛进步和生活节奏的不断加快&#xff0c;传统的长篇电视剧和电影已不能完全满足所有人的需求。短剧&#xff0c;由于其简短、快速、直接的特性&#xff0c;正在逐步成为一种文化新趋势。短剧系统正是这一趋势的典型代表&#xff0c;它以独特…

Ansys Mechanical|使用Trace Mapping建立PCB板的有限元模型

Trace Mapping需要使用ECAD的方法 传统方法 vs ECAD方法 传统方法既繁琐又费时。以下是一些数据&#xff1a; 导出电路板布局的step文件大约需要30分钟。 导入Ansys SpaceClaim中大约需要10分钟。 进行布尔运算和共享拓扑操作大约需要24小时甚至更久。 而ECAD方法更加快速且…

CV每日论文--2024.6.12

1、PGSR: Planar-based Gaussian Splatting for Efficient and High-Fidelity Surface Reconstruction 中文标题&#xff1a;PGSR&#xff1a;基于平面的高斯溅射&#xff0c;用于高效、高保真表面重建 简介&#xff1a;这项研究关注于3D高斯喷洒(3DGS)技术,该技术因其高质量渲…

探索生成式AI的未来:Chat与Agent的较量与融合

近年来&#xff0c;生成式人工智能&#xff08;AI&#xff09;不仅在技术界引起了广泛关注&#xff0c;更成为了推动多个行业革新的关键力量。这种技术之所以备受瞩目&#xff0c;不仅在于其独特的创造性和高效性&#xff0c;还在于它对未来商业模式和社会结构可能产生的深远影…

Java的Mybatis框架中#{}与${}使用心得

Java的Mybatis框架中#{}与${}使用心得 在MyBatis框架中&#xff0c;#{}和${}都是用来动态地向SQL语句中插入值的&#xff0c;但它们的处理方式和用途有所不同 #{} 安全&#xff1a;#{}是预编译处理&#xff0c;能够有效防止SQL注入。它会将参数看作一个占位符&#xff0c;在…

servlet梦想酒店管理系统

梦想酒店管理系统 酒店管理系统分为管理端&#xff0c;和用户端&#xff0c; 用户端可以查看酒店客房&#xff0c;预定酒店系统&#xff0c;查询预定信息。 管理端&#xff1a;用户管理&#xff0c;类型&#xff0c;房间管理&#xff0c;业务管理&#xff0c;统计分析。 技术&…