Google实习总结

知乎回答:https://www.zhihu.com/question/336859540/answer/761912465

我的Google账号:xiangyunding@google.com,但check out之后就不能用了。

感谢以下个人/组织:

  • host: wenjies,co-host: chaoyuel
  • recruiter:irene, rosy, yun, etc.
  • 帮我内推的sunyq和帮我介绍内推的jzh
  • 帮我review代码,还有其他帮助我的Googler
  • 一起入职的小伙伴们
  • Dataz group
  • Google

申请过程

关于正式的招聘流程和最新的招聘信息,请关注:

我大概的流程是这样的:

  • 2018.12.23 在群里看到转发的招实习生的通知,就发了简历申请。
  • 2018.12.26 收到官方邮件,填写申请表格,主要是:
    • 基本信息,简历
    • 期望的面试时间,我选的是寒假之后的。
  • 2019.1.4 通过recruiter review
  • 2019.2.26 第一轮电话面试。两道算法题,都做对了。
  • 2019.3.7 第二轮电话面试。还是两道算法题,也都做对了。
  • 2019.3.13 收到offer。与hr商量实习时间,还考虑到期末可能事情比较多,最后确定了5.6-8.30。因为Google的实习生要求实习天数60-70天(不能少也不能超)。
  • 2019.5.6 入职

说实话,最开始只是随便投了一下,都没想到真的能过。几点经验总结:

  • 一定要事先调试好设备和网络(需要用google docs)。
  • 多与面试官交流。Google不喜欢闷着头做题的人。

Google的申请流程很正规,一步一步很清楚,不过流程也比较漫长。每周recruiter都会发邮件sync进度,有问题也可以发邮件咨询。Google对实习生招聘要求的很严格,每位FTE想招实习生,都要写一份详细的报告,实习生总数也控制的很严。今年实习生与往年相比招了很多,北京上海两个办公室一共140人左右(包括RS,SWE,ML SWE和EP)。另外Google招聘对女生很照顾,即使不算EP,感觉男女数量也差不多(假设男生女生水平一样,招聘的男女比应该与高校计算机专业的男女比一样才对,看看贵系男女比我就不好说什么了)。学校和专业虽然说不考虑,但我认识的intern还是清北居多,并且硕博比较多。

有想申请的同学请关注的官方消息。我虽然离职了应该也可以帮忙推简历的。至于实习待遇方面,可以说工资、工作环境没有其他公司能跟Google比了。具体薪资应该不让说,但可以给个参考价,比头条多不少,而且包三餐,而且发好多房补。很多人跟我一样可以住学校,房子根本没花钱,但Google就是这么大方。

实习

实习项目是WikiTrust Revamp,维基百科的恶意修改检测。因为签了保密协议,这部分就不详细讲了。只是做了一点微小的工作。据说这个project的由来是,去年特朗普发现维基百科经常被恶搞,就在twitter上@了一下Google。WikiTrust很久之前有人搞过,不过效果非常差,于是Google就安排了几个人做新的WikiTrust,他们就取了个名字叫WikiTrust Revamp,修补的意思。当然整个Dataz组做的事情就很多了。

Google作为世界顶级的软件公司,内部工具和文档、开发流程、代码质量控制都做的太成熟了,之前上软工的时候还觉得这些东西好麻烦,为什么要写单元测试,为什么要搞文档和注释,来到Google才发现这些东西是真的游泳。在Google提交每一份代码,首先都要通过g4 fix自动调整一下风格,比如每行不超过80字符,include顺序等等。然后至少两人review,包括代码逻辑、代码风格、可读性、可维护性检查,觉得不好的地方可以写comments。然后,针对每一个comments修改代码,重复上面的流程。在这之间系统会运行presubmit(包括很多静态检查、运行所有相关的单元测试等)。直到所有的reviewer都认为可以提交了,并且presubmit也通过了,这时才可以点击submit按钮,将这份代码提交到代码库里。我交的最慢的一个cl交了两个多星期,是临时找了一位美国那边的精通C++的同事review,给我提了五十多条comments,改的时候整个页面comments比code还多。注释和单元测试就更不必说了,没有这些不可能让你提交的。Google内部的工具和文档真的太全面了,比如moma、codesearch、critique、piper、cider、flume等等,而且都有十分详细的文档或codelab帮助使用。除了这些开发用的工具之外,其他用的也几乎都是Google自家的产品:查资料用Google search,邮件用gmail,浏览器用Chrome,文件用Google docs,表格用Google sheets,ppt用Google slides,开会用meetings,英文看不懂的用Google translate,有问题上moma(内部的search),发消息用hangout chat,等等。Google的基础设施真的让人很震撼。

工作环境方面,真的是太太太太太好了。一日三餐,零食水果尽情享受,还有健身房、按摩椅、乒乓球台、游戏机……还有好多我没有尝试过的。据我观察,正式员工大多9-10点到公司,下午5-6点就走,晚饭后公司就基本没人了。正式员工都是采用OKR工作法,同事之间、上下级之间交流也非常轻松愉悦。由于Google是美国企业,入职时还给我们宣传Google的价值观。印象最深的是比较注重个人隐私,然后开放自由之类的。

Intern offsite去的是这个地方:http://www.dianping.com/shop/97821752 。我个人不是很喜欢这种室内娱乐场所,不过这是大家投票决定的。午饭每人100元budget随意吃。晚餐去的这里:http://www.dianping.com/shop/69719009 ,人均270的自助。Offsite这天工资还照发,舒服。

总结

其实开始找内推的时候真的没想到能来。并且后面找工作的时候才发现,Google的实习经历真的管用,简历几乎没有被卡过(我清华同学本科无实习的简历有时就会被卡)。

TBD

Collection of Movies I Have Watched

This is a list of the movies I have watched.

总结一下。不然都忘了。按汉语拼音排序。


电影

007:大战皇家赌场(Casino Royale)

007:黑日危机(The World Is Not Enough)

007:大破量子危机(Quantum of Solace)

2012

A

A计划

A计划续集

爱乐之城(La La Land)

阿甘正传(Forrest Gump)

阿凡达(Avatar)

B

白蛇:缘起

白蛇2:青蛇劫起

宝贝计划

爆裂鼓手(Whiplash)

变形金刚(Transformers)

变形金刚2:卷土重来(Transformers: Revenge of the Fallen)

变形金刚3:月黑之时(Transformers: Dark of the Moon)

变形金刚4:绝迹重生(Transformers: Age of Extinction)

白日梦想家(The Secret Life of Walter Mitty)

C

楚门的世界(The Truman Show)

刺杀小说家

D

地心引力(Gravity)

敦刻尔克(Dunkirk)

独立日(Independence Day)

独立日2:卷土重来(Independence Day: Resurgence)

碟中谍4:幽灵协议(Mission: Impossible – Ghost Protocol)

碟中谍5:神秘国度(Mission: Impossible – Rogue Nation)

碟中谍6:全面瓦解(Mission: Impossible – Fallout)

大白鲨(Jaws)

盗梦空间(Inception)

当幸福来敲门(The Pursuit of Happyness)

帝国的毁灭(德语:Der Untergang)

狄仁杰之通天帝国

F

复仇者联盟3:无限战争(Avengers: Infinity War)

风雨哈佛路(Homeless to Harvard: The Liz Murray Story)

釜山行

G

功夫

H

黑客帝国(The Matrix)

黑客帝国2:重装上阵(The Matrix Reloaded)

黑客帝国3:矩阵革命(The Matrix Revolutions)

活火熔城(Volcano)

后天(The Day After Tomorrow)

火星人玩转地球(Mars Attacks!)

荒岛余生(Cast Away)

黑洞表面(Event Horizon)

虎!虎!虎!

J

金钱帝国

教父(The Godfather)

警察故事

警察故事2

警察故事3:超级警察

警察故事4:简单任务

尖峰时刻(Rush Hour)

尖峰时刻2(Rush Hour 2)

尖峰时刻3(Rush Hour 3)

巨齿鲨(The Meg)

惊变28天(28 Days Later)

金刚(King Kong)

金刚:骷髅岛(Kong:Skull Island)

基督山伯爵(The Count of Monte Cristo)

姜子牙

K

控方证人(Witness for the Prosecution)

快餐车

困在时间里的父亲(The Father)

L

流浪地球

料理鼠王(Ratatouille)

浪潮(德语:Die Welle)

乱世佳人(Gone with the Wind)

镰仓物语

M

美丽人生(意大利语:La vita è bella)

美女与野兽(Beauty and the Beast)

湄公河行动

模仿游戏(The Imitation Game)

N

哪吒之魔童降世

你的名字

纳尼亚传奇(The Chronicles of Narnia)

南极大冒险(Eight Below)

P

贫民窟的百万富翁(Slumdog Millionaire)

Q

千与千寻

R

熔炉(Silenced)

人再囧途之泰囧

S

生化危机(Resident Evil)

生化危机2:启示录(Resident Evil: Apocalypse)

生化危机3:灭绝(Resident Evil: Extinction)

生化危机4:来生(Resident Evil: Afterlife)

生化危机5:惩罚(Resident Evil: Retribution)

生化危机6:终章(Resident Evil: The Final Chapter)

死亡诗社(Dead Poets Society)

速度与激情(The Fast and the Furious)

速度与激情2(2 Fast 2 Furious)

速度与激情3:东京飘移(The Fast and the Furious: Tokyo Drift)

速度与激情4(Fast & Furious)

速度与激情5(Fast Five)

速度与激情6(Fast & Furious 6)

速度与激情7(Fast & Furious 7)

速度与激情8(The Fate of the Furious)

速度与激情:特别行动(Hobbs & Shaw)

速度与激情9(Fast & Furious 9)

闪灵(The Shining)

T

天气之子

泰坦尼克号(Titanic)

头号玩家(Ready Player One)

逃出克隆岛(The Island)

唐人街探案

唐人街探案2

唐人街探案3

太空旅客(Passengers)

V

V字仇杀队(V for Vendetta)

W

误杀

我不是药神

午夜凶铃

午夜凶铃2:贞子缠身

网络迷踪(Searching)

我不是潘金莲

我是谁

X

西虹市首富

新警察故事

猩球崛起(Rise of the Planet of the Apes)

猩球崛起2:黎明之战(Dawn of the Planet of the Apes)

猩球崛起3:终极之战(War for the Planet of the Apes)

肖申克的救赎(The Shawshank Redemption)

西西里的美丽传说

星际穿越(Interstellar)

辛德勒的名单(Schindler’s List)

血战钢锯岭(Hacksaw Ridge)

Y

英伦对决(The Foreigner)

异形(Alien)

异形2(Aliens)

异形3(Alien 3)

异形4(Alien Resurrection)

一球成名(Goal!)

一路逆风

一出好戏

Z

战狼2

拯救大兵瑞恩(Saving Private Ryan)

蜘蛛侠:英雄远征(Spider-Man: Far From Home)

终结者(The Terminator)

终结者2:审判日(Terminator 2: Judgment Day)

终结者3:机器觉醒(Terminator 3:Rise of the Machines)

终结者2018(Terminator Salvation)

侏罗纪公园(Jurassic Park)


电视剧

神探夏洛克(Sherlock)

非自然死亡(Unnatural)

行尸走肉(The Walking Dead)


持续更新中。。。

Leetcode 1125. Smallest Sufficient Team

题目

https://leetcode.com/problems/smallest-sufficient-team/

有n个数,m个数集,要从中选出k个数集,使得这k个集合的并集包含这n个数。求最小的k。

n <= 16, m <= 60

做法

状态压缩动态规划。设f[S]表示包含集合S中的数的最少集合数。枚举S的每一个子集A,那么f[S] = min(f[A] + f[S - A])。通过给定的m个集合初始化即可。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Solution {
public:

int n;

void getans(const vector<int>& from, const vector<int>& go, int S, vector<int>* ans) {
if (S == 0) return;
if (go[S] != -1) {
ans->push_back(go[S]);
return;
}
int subset = from[S];
if (subset == 0 || subset == S) return;
getans(from, go, subset, ans);
getans(from, go, S ^ subset, ans);
}

vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
n = req_skills.size();
vector<int> f(1 << n);
vector<int> go(1 << n);
f[0] = 0;
for (int i = 1; i < f.size(); i++) {
f[i] = 1e8;
}
for (int i = 0; i < go.size(); i++) {
go[i] = -1;
}
for (int i = 0; i < people.size(); i++) {
int S = 0;
for (const string& skill : people[i]) {
for (int k = 0; k < req_skills.size(); k++) {
if (req_skills[k] == skill) {
S |= 1 << k;
break;
}
}
}
// 枚举S的子集
for (int subset = S; subset > 0; subset = (subset - 1) & S) {
f[subset] = 1;
go[subset] = i;
}
}
vector<int> from(1 << n);
for (int S = 0; S < f.size(); S++) {
for (int subset = S; subset > 0; subset = (subset - 1) & S) {
int num = f[subset] + f[S ^ subset];
if (num < f[S]) {
f[S] = num;
from[S] = subset;
}
}
}
vector<int> ans;
getans(from, go, (1 << n) - 1, &ans);
sort(ans.begin(), ans.end());
return ans;
}
};

下面分析时间复杂度。显然我们枚举了n个数的所有子集的所有子集。包含k个数的子集有$C_n^k$个,他们子集都分别有$2^k$个。因此时间复杂度为:
$$\sum_{k=0}^{n}C_n^k\times2^k=C_n^0\times2^0+C_n^1\times2^1+C_n^2\times2^2+…+C_n^n\times2^n$$
高中时学过杨辉三角,可以知道上面这个式子就是$(2+1)^n$的展开式。因此总时间复杂度O($3^n$),$3^{16}=43046721$,四千多万,可以通过。

Leetcode 1147. Longest Chunked Palindrome Decomposition

题目

https://leetcode.com/problems/longest-chunked-palindrome-decomposition/

给一个字符串,要求将其分割成a1, a2…ak,每一份长度>0,并且a[i] = a[k + 1 - i]。例如”ghiabcdefhelloadamhelloabcdefghi”可以分割为”(ghi)(abcdef)(hello)(adam)(hello)(abcdef)(ghi)”。求最大的k。字符串长度<=1000。

做法

本来看n<=1000觉得是O($n^2$)的做法,枚举中间一块的长度,然后从中间向两边贪心,判断字符串相等使用hash。后来发现,直接从两边往中间贪心就行了。。连hash都不用,直接暴力判断。这也是hard题。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
int longestDecomposition(string text) {
int n = text.length();
int ans = 0;
int l = 0, r = 0;
while (r * 2 + 1 < n) {
if (text.substr(l, r - l + 1) == text.substr(n - r - 1, r - l + 1)) {
ans += 2;
l = r + 1;
r = l;
continue;
}
r++;
}
if (n % 2 == 0 && l == n / 2) return ans;
return ans + 1;
}
};

Leetcode 1157. Online Majority Element In Subarray

题目

https://leetcode.com/problems/online-majority-element-in-subarray/

给定一个长度为n的数组,m次查询,每次查询[l, r]区间内出现次数>=threshold的数是哪个。保证 threshold * 2 > r - l + 1 。强制在线。n, m <= 20000。

做法

暴力做法:对于每个query,扫描l到r区间中的数,用hash表存下每个数的出现次数。时间复杂度O(n*m)。

这个题中要求的数是majority,也就是出现次数大于总次数的一半。这是一个很强的限制。我们可以发现,暴力算法处理慢的地方在于区间较长的时候,也就是threshold较大的时候。而threshold较大时,满足条件的数的个数就会很少!

于是可以取$\sqrt{n}$作为阈值,分两种情况讨论:

  • 若threshold<$\sqrt{n}$,则区间长度<$2\sqrt{n}$,按照暴力做法求解,每次询问时间复杂度O($\sqrt{n}$)。
  • 若threshold>$\sqrt{n}$,满足这样条件的数不超过$\frac{n}{\sqrt{n}}=\sqrt{n}$个。因此在开始时进行预处理,求出这$\sqrt{n}$个数,那么只需要在查询时知道每一个数在[l, r]中出现了多少次。我的方法是对每个数维护一个长度为n的前缀和数组,这样O(1)的时间即可得到其在[l, r]中的出现次数,每次询问的时间复杂度为O($\sqrt{n}$)。

总时间复杂度O($n\sqrt{n}$)。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class MajorityChecker {
public:

vector<int> arr;
vector<int> frequent;
vector<vector<int>> sum;

MajorityChecker(vector<int>& arr) {
this->arr = arr;
map<int, int> count;
for (int x : arr) {
count[x]++;
}
for (auto it = count.begin(); it != count.end(); it++) {
if (it->second > 100) {
frequent.push_back(it->first);
}
}
sum.resize(frequent.size());
for (int i = 0; i < frequent.size(); i++) {
int x = frequent[i];
sum[i].resize(arr.size());
for (int j = 0; j < arr.size(); j++) {
if (x == arr[j]) {
sum[i][j] = 1;
}
if (j > 0) {
sum[i][j] += sum[i][j-1];
}
}
}
}

int work1(int left, int right, int threshold) {
unordered_map<int, int> count;
for (int i = left; i <= right; i++) {
if (++count[arr[i]] >= threshold) {
return arr[i];
}
}
return -1;
}

int work2(int left, int right, int threshold) {
for (int i = 0; i < frequent.size(); i++) {
int cnt = sum[i][right] - (left == 0 ? 0 : sum[i][left - 1]);
if (cnt >= threshold) {
return frequent[i];
}
}
return -1;
}

int query(int left, int right, int threshold) {
if (threshold <= 100) {
return work1(left, right, threshold);
}
else {
return work2(left, right, threshold);
}
}
};

在Google被人逼着养成了良好的代码风格,好处就是代码比较容易看懂,坏处就是写的过程非常痛苦。

其他人的做法

交了之后看了一下discuss(这个题暂时还没有solution),发现有些人用线段树做的。这种做法基于摩尔投票算法。这个算法专门用来求数组中的majority,也就是出现次数大于一半的数。伪代码如下:

1
2
3
4
5
6
Initialize an element m and a counter i with i = 0
For each element x of the input sequence:
If i = 0, then assign m = x and i = 1
else if m = x, then assign i = i + 1
else assign i = i − 1
Return m

看完大概就能明白,这个算法只能做找majority这么一件事情,并且如果没有majority它也会返回一个值,需要再check一下结果是不是majority。

这个题正好是要找majority。不过,我没怎么想清楚他们是怎么用线段树维护这个东西的。他们的代码写的我觉得有点问题,但是竟然能过。这种方法的时间复杂度是O($n\log_{2}^{2}{n}$),实际跑起来比我的做法还要慢一些。

换机Huawei nova 5 Pro

今天买了一部新的华为nova 5 pro,换掉了用了三年的iphone 6s plus。

搭梯子

拿到手机后,先把不需要的能卸载的app全都卸载,华为助手之类的全部禁用。然后开始搭梯子。我用的是自己配的shadowsocks,可以到 https://github.com/shadowsocks/shadowsocks-android 下载。shadowsocks服务器端搭建方法可参考 https://www.cnblogs.com/iStu/p/9992535.html 。服务器是之前在 https://www.hostwinds.com/ 租的。配置好后确保能通过浏览器访问Google即可。

安装谷歌服务框架

国产Android手机上默认都不会预装谷歌服务框架。对于现在还在Google实习的我来说没有Google怎么行呢。安装谷歌服务框架可以参考:https://www.zhihu.com/question/333903896/answer/761587221

下载谷歌服务助手之后,一步一步安装即可。这样就安装了谷歌服务框架和Google Play Store。然后就可以在Play Store里下载想要的应用了。如果不小心把Play Store删了也没事,照上面的步骤再来一遍就行了。

有一些Google应用不能通过国区的Play Store账号下载,比如Google Drive,Google Docs等。可以参考 https://www.zhihu.com/question/21999528/answer/447913645 切换地区。

后续

后面装sim卡,恢复微信备份之类的就没必要写了。恢复备份需要电脑和手机连同一wifi,但是不知为什么我连公司的GoogleGuestPSK不行,最后用原来的手机开了个热点才备份好的。全面屏真的爽。而且还支持快充,3000块钱也值了。iphone留着当备用机了。

Build Blog on Github Pages with Hexo

Blog Repository

https://github.com/xindubawukong/xindubawukong.github.io

This repo only contains static html files. The comments function of the blog is based on the issues of this repo.

References

https://pages.github.com/

https://hexo.io/

https://zhuanlan.zhihu.com/p/26625249

http://menuet.xyz/technology/tool/Hexo%E9%97%AE%E9%A2%98%E6%80%BB%E7%BB%93/

主题:https://github.com/wayou/hexo-theme-gstyle

图床:https://postimages.org/

markdown公式渲染:https://zhuanlan.zhihu.com/p/36302775

评论功能:https://github.com/utterance/utterances

每页显示个数设置:http://www.yuzhewo.com/2015/11/21/Hexo%E7%A8%8B%E5%BA%8Farchive%E9%A1%B5%E9%9D%A2%E6%95%B0%E9%87%8F%E8%AE%BE%E7%BD%AE/