字节跳动校招情况分析
在写完了绝对顶流 华为 和近两年炙手可热的 比亚迪 的校招薪资之后,不少同学点名要看「字节跳动」。
确实,玩归玩,闹归闹,别拿字节开玩笑。
先来看看和公众号读者相关性较高的岗位校待遇:
研发 | 算法 | 签字费 | |
---|---|---|---|
白菜 | 20k~23k | 22k~25k | 1w |
SP | 24k~27k | 26k~29k | 1w |
SSP | 28k~33k | 30k~36k | 1w |
字节合同薪资是 12-18 薪,但大多数人通常都是直接 15 薪。
因此直接用月薪*15,计算年包,是一个比较合理的做法。
- 研发:白菜年包 30w
34.5w;SP 年包 36w40.5w;SSP 年包 42w~49.5w - 算法:白菜年包 33w
37.5w;SP 年包 39w43.5w;SSP 年包 45w~54w
字节跳动今年校招的薪资,无论是横向(与其他互联网大厂对比),还是纵向(与往年自身的校招薪资对比)都是比较高的。
薪资是一方面,进入字节,对部门需要尤其看重。
这两年,字节对各个赛道的围剿,开始进入「止损」或「合并」阶段。
一些连普罗大众都知道的事,是对教培的彻底放弃,以及对游戏和 Pico 业务的逐步关停。
而可能只有企业内部才了解的,还包括懂车帝、住小帮、小荷健康合并到抖音集团。
业务彻底放弃,意味着原地解散。
这对那些已经在字节做了多年,大礼包动辄几十万的老员工来说,至少是有缓冲空间的。
但如果是应届生转正不久就经历的话,这变化确实不好拥抱。
对于员工而言,解散或合并总归不是一个好的安排。但对公司来说,真就未必。
有些业务的开拓,从一开始就注定只会走这两条路:要么解散,要么合并,不会是做大做强。
这引导我们不能用「对行业的基本认识」来衡量大公司的拓展业务分支。
创建分支的「强目的性」往往会带来业务的「强不确定性」。
这听起来,很矛盾。
可以用「字节宣布逐步解散游戏业务」来进行分析。
2023年11月27日,字节宣布逐步关闭游戏业务。
现在外界对字节这一决策的主流解读是什么?
普遍对该决策的解释,都绕不开2023年12月22号由国家新闻出版署颁布《网络游戏管理办法(草案征求意见稿)》。
仿佛字节是穿越者,又或者提前收到了"通知"一样。
先不说,字节还没有上市,这个所谓的"先行操作"不会产生什么避免财富蒸发或推波助澜的作用。
再说,字节作为游戏赛道中一位特殊的后来者,恰好是少数可以把消息当作利好解读的一方。
意见稿中的「高额氪金限制」、「概率性规则设定」,对于网易和腾讯等老牌游戏厂,影响较大;「首次充值」对于大多仅靠首充活着的小游戏厂,属于致命影响。
至于字节?
大多游戏都还没走过烧钱阶段,意见稿限制,和我有啥关系?
总的来说,字节基本上处于,一纸意见稿打下来,同行们人均伤害 80,我方受伤害不足 10 的水平。
所以,任何一个具备独立思考能力的人,都能发现所谓「字节提前得知"意见稿",解散游戏业务」只是最有流量的写法,不会是事实本身。
那为啥突然关停游戏业务?
这就讲回刚刚说的「有些业务的开拓,从一开始就注定关停解散」的。
理解关停,就要先搞清楚,为什么字节刚开始会想做游戏。
当时还是"头腾大战"打得火热的 2019 年,抖音已经是现象级的 App,腾讯的「王者荣耀」、「绝地求生」和「刺激战场」也用户数纷纷破亿。
双方就「游戏画面是否被用于商业化」发生纠纷,很长一段时间内,抖音和火山系 App 都搜索不到腾讯游戏相关视频。
当时,抖音方面表示:腾讯主张,用户在自己手机上玩王者荣耀录屏视频权利属于腾讯。
腾讯则表示:没提出过这样的主张。
表示归表示,腾讯还是就「西瓜视频以平台名义开设《王者荣耀》直播专区,招募主播是否合法」一事诉至法院。
最终,广州知识产权法院做出裁定,明确西瓜视频停止直播《王者荣耀》游戏内容,原因是侵害腾讯对《王者荣耀》享有的著作权。
同年,字节正式布局游戏。
看到这里,你应该明白了。
字节从成立游戏部门开始,就并非为了做好游戏,而仅仅是为了铺路抖音内容生态。
这一定程度也解释了,为什么这些年来,字节游戏总是不温不火,甚至可以说摇摆不定。
现如今,字节和腾讯关系缓和,不仅仅是腾讯游戏官号入驻,各种录屏和二创在抖音上能播,甚至越来越多腾讯系的游戏主播都选择签约抖音。
对字节而言,既然在游戏行业大力出不了奇迹,整个字节游戏加起来也抵不过一个王者荣耀为抖音提供的内容生态。
关了就关了,一个好理解且简单的商业决定。
到这里,可能有同学会问,那字节之前投游戏这么多钱,白砸了?
怎么说呢。
做游戏,关游戏,看似矛盾的两步操作,不能说是绝对好棋,但都为字节带来了想要的结果。
看着结果,去嘲笑过程,从逻辑上就不成立。
如果没有当时字节进击游戏的决心和力度,是不是一定有如今的头腾关系缓和,抖音直接坐拥腾讯完整游戏内容生态呢?
大概率不会。
...
说到字节校招,在牛客网上,看到一个很有意思的帖子:
这位同学,在一面的时候,被面试官问了个问题,当场没忍住,笑了出来。
这个问题是:平时写代码吗?
怎么说呢,刚开始我还能理解他说的笑点。
但看完他最后一段的自述,我基本确定他不是一个适度自信的小孩。
我不知道,当时这位字节的面试官,是否有理解到他笑容里的意思。
我相信如果面试官 Get 到这位同学的意思,一定会在他自信回答完「当然写代码啊」后,自然过渡到「那就做道算法题吧」。
最后,在对面汗流浃背的时候,不忘了 Call Back 一下原问题,平时真的写代码吗?🤣🤣
总的来说,我认为能问出这样的问题,很有可能是一位面试经验丰富的面试官,年轻的,只是这位同学。
通过该帖子,可以指出两个问题,一个是「在面试中应该如何保持专业和尊重」,另外一个更内核的问题是「适度自信和过度自信的边界在哪」。
今天篇幅差不多了,留到下次。
...
好了,现在到我问了:大家平时写代码吗?
不管你写不写,我都要向你介绍一道「字节跳动」相关的算法题。
题目描述
平台:LeetCode
题号:76
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。
如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
示例 1:
arduino
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
示例 2:
ini
输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。
示例 3:
arduino
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
提示:
m == s.length
n == t.length
- <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = m , n < = 1 0 5 1 <= m, n <= 10^5 </math>1<=m,n<=105
s
和t
由英文字母组成
进阶:你能设计一个在 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( m + n ) O(m+n) </math>O(m+n) 时间内解决此问题的算法吗?
滑动窗口
定义两个长度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 60 60 </math>60(足够存下所有字母种类)的数组 c1
和 c2
,用于存储字符频率。其中 c1
用于记录字符串 t
中字符的频率,c2
用于记录当前滑动窗口内字符的频率。
设定好字母与频率数组下标的映射关系:小写字母 a-z
对应下标 0-25
,大写字母 A-Z
对应下标 26-51
。
使用变量 tot
来记录还需要匹配的字符种类数,当 tot = 0
代表当前滑动窗口对应的子串能够实现对 t
的覆盖,即任意字符满足 <math xmlns="http://www.w3.org/1998/Math/MathML"> c 2 [ i ] ≥ c 1 [ i ] c2[i] \geq c1[i] </math>c2[i]≥c1[i]。
使用双指针 j
和 i
表示滑动窗口的左右边界。从前往后遍历字符串 s
,在每个位置上更新字符频率数组 c2
。若 c2
中字符的频率达到了 c1
中的字符频率,则将 tot
减 1,表示一个字符已经匹配完成。
每当右边界往后移动一步之后,滑动窗口会增加一个字符。此时我们检查左边界能否右移,同时不会使得 tot
变大。即每次右边界右移后,我们检查左边界 <math xmlns="http://www.w3.org/1998/Math/MathML"> c 2 [ j ] > c 1 [ j ] c2[j] > c1[j] </math>c2[j]>c1[j] 是否满足:
- 若满足:说明当前左边界指向字符并非必须,当前子串 <math xmlns="http://www.w3.org/1998/Math/MathML"> s [ j . . . i ] s[j...i] </math>s[j...i] 必然不是最短子串。我们让左边界
j
进行右移,并重复进行左边界 <math xmlns="http://www.w3.org/1998/Math/MathML"> c 2 [ j ] > c 1 [ j ] c2[j] > c1[j] </math>c2[j]>c1[j] 的检查,直到窗口不能再收缩 - 若不满足:说明当前窗口没有任何一个后缀字符串能够实现对
t
的覆盖,我们并不能对窗口实现收缩
每次对窗口移动完成后,我们检查当前 tot
是否为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0(对字符串 t
的覆盖是否完成),若为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0 则尝试用当前窗口对应的字符串 <math xmlns="http://www.w3.org/1998/Math/MathML"> s [ j . . . i ] s[j...i] </math>s[j...i] 更新 ans
。
Java 代码:
Java
class Solution {
public String minWindow(String s, String t) {
int n = s.length(), tot = 0;
int[] c1 = new int[60], c2 = new int[60];
for (char x : t.toCharArray()) {
if (++c1[getIdx(x)] == 1) tot++;
}
String ans = "";
for (int i = 0, j = 0; i < n; i++) {
int idx1 = getIdx(s.charAt(i));
if (++c2[idx1] == c1[idx1]) tot--;
while (j < i) {
int idx2 = getIdx(s.charAt(j));
if (c2[idx2] > c1[idx2] && --c2[idx2] >= 0) j++;
else break;
}
if (tot == 0 && (ans.length() == 0 || ans.length() > i - j + 1)) ans = s.substring(j, i + 1);
}
return ans;
}
int getIdx(char x) {
return x >= 'A' && x <= 'Z' ? x - 'A' + 26 : x - 'a';
}
}
C++ 代码:
C++
class Solution {
public:
string minWindow(string s, string t) {
int n = s.length(), tot = 0;
vector<int> c1(60), c2(60);
for (char x : t) {
if (++c1[getIdx(x)] == 1) tot++;
}
string ans = "";
for (int i = 0, j = 0; i < n; i++) {
int idx1 = getIdx(s[i]);
if (++c2[idx1] == c1[idx1]) tot--;
while (j < i) {
int idx2 = getIdx(s[j]);
if (c2[idx2] > c1[idx2] && --c2[idx2] >= 0) j++;
else break;
}
if (tot == 0 && (ans.empty() || ans.length() > i - j + 1)) ans = s.substr(j, i - j + 1);
}
return ans;
}
int getIdx(char x) {
return x >= 'A' && x <= 'Z' ? x - 'A' + 26 : x - 'a';
}
};
Python 代码:
Python
class Solution:
def minWindow(self, s: str, t: str) -> str:
def getIdx(x):
return ord(x) - ord('A') + 26 if 'A' <= x <= 'Z' else ord(x) - ord('a')
n, tot = len(s), 0
c1, c2 = [0] * 60, [0] * 60
for x in t:
idx = getIdx(x)
c1[idx] += 1
if c1[idx] == 1:
tot += 1
ans = ""
j = 0
for i in range(n):
idx1 = getIdx(s[i])
c2[idx1] += 1
if c2[idx1] == c1[idx1]:
tot -= 1
while j < i:
idx2 = getIdx(s[j])
if c2[idx2] > c1[idx2]:
j += 1
c2[idx2] -= 1
else:
break
if tot == 0 and (not ans or len(ans) > i - j + 1):
ans = s[j:i + 1]
return ans
TypeScript 代码:
TypeScript
function minWindow(s: string, t: string): string {
let n = s.length, tot = 0;
const c1 = Array(60).fill(0), c2 = Array(60).fill(0);
for (const x of t) {
if (++c1[getIdx(x)] === 1) tot++;
}
let ans = "";
for (let i = 0, j = 0; i < n; i++) {
const idx1 = getIdx(s[i]);
if (++c2[idx1] == c1[idx1]) tot--;
while (j < i) {
const idx2 = getIdx(s[j]);
if (c2[idx2] > c1[idx2] && --c2[idx2] >= 0) j++;
else break;
}
if (tot == 0 && (!ans || ans.length > i - j + 1)) ans = s.substring(j, i + 1);
}
return ans;
}
function getIdx(x: string): number {
return x >= 'A' && x <= 'Z' ? x.charCodeAt(0) - 'A'.charCodeAt(0) + 26 : x.charCodeAt(0) - 'a'.charCodeAt(0);
}
- 时间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n + m ) O(n + m) </math>O(n+m)
- 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( C ) O(C) </math>O(C),其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> C = 26 × 2 C = 26 \times 2 </math>C=26×2,为字符集大小
我是宫水三叶,每天都会分享算法题解,并和大家聊聊近期的所见所闻。
欢迎关注,明天见。
更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉