王远轩:北美求职记

来源:王远轩的博客

最近签掉了 offer,找工作的事情算是告一段落。在这里写一点面试体验和心得,希望对有兴趣去北美工作的朋友有所帮助。

先简单介绍下自己,国内硕士在读,明年毕业,没有牛 paper,也没参加过 ACM-ICPC 竞赛。在实验室做过内核、虚拟机和 Android 底层相关的研究工作,接过一些网页和移动开发的外包,2011 年开始在字节社兼职负责后台开发。另外也经常上 Stackoverflow 和 GitHub

这次决定直接申请美国的职位后,由于心里没底,不知道国外公司招聘的难度,所以一开始投了很多公司。几个大公司都找人内推或者直接投了,小公司也投了不少,比如 Foursquare、Path、Pinterest 和 Square 等都试了。当时甚至在手机上找了一圈应用,把可能涉及后端开发的应用都投了一遍。不过大多数公司都没给我安排面试,只有 Microsoft、Google、Facebook、Twitter 和 Hulu 这五家公司愿意给我面试机会。

一般来说,国内毕业后直接投国外公司,会比出国留学毕业后找工作的难度大一些。除了语言因素之外,我了解到的主要原因在于工作签证,出国留学毕业后可以通过 OPT 签证入职,之后再过渡到 H-1B 签证。而国内毕业的学生只能通过 H-1B,这意味着要等到第二年的十月份才能入职。好在 Google、Facebook 等公司不太介意这个问题,还是会欢迎国内的应届生申请。

校招的 HR 一般会有各自的职责。比如 technical sourcer 负责发现有希望进入自己公司的应届生;recruiter coordinator 会帮助 recruiter 安排面试者的面试时间、面试官,以及 onsite 面试时帮助面试者订机票和酒店;staffing consultant 则负责发 offer 以及介绍公司的具体福利制度,并解释面试者相关的问题。不同公司的 HR 职责的分法自然也不一样,我在 Facebook 的面试过程中只和两位 HR 联系过,而在微软的面试过程中则联系过五六位 HR。

在面试流程方面,相比我了解到的国内公司的面试,国外公司的面试安排上会更人性化一些。例如安排面试时间时,HR 一般会先让你给出几个空闲的时间点,然后他们再从这些时间中给你安排面试。此外在为你安排 onsite 的住宿时,也会询问你有没有相关的要求。

关于面试题目,大多数公司都比较侧重面试者对基本的数据结构和算法的掌握程度,以及把这些内容实现为实际代码的能力(一般会要求你选一个语言实现,而不允许用伪代码)。越是规模大的公司越注重这些基本功,而小公司除此之外还会考察你的开发经验,例如对某个框架的了解和性能优化方面的技巧。关于这一点区别我的理解是大公司里面会有自己的框架和开发工具,面试者的基本功好就能比较快的上手;而小公司一般用社区现有的工具,所以已有的开发经验可以直接用在将来的工作中。

下面是这几个公司的面试细节,有些公司因为在 onsite 面试的时候签了 NDA,所以没法透露具体的面试题,还请见谅。

Microsoft

微软是我最早投的公司之一,托了在微软总部工作的一位学长帮忙内推。面试包括一轮 HR 面和四轮 onsite 面。

申请了一个多月后一直都没有反应,直到微软国内招聘的前一天,北京的 HR 打电话问我是不是投过微软的职位,要我参加第二天上海站的笔试。

笔试过后,又过了一个多月,收到了微软一位招聘人员的邮件,问我是不是对微软北美的职位有兴趣,要我填一份基本情况的问卷,里面有问到其他公司的面试进度。我当时已经收到了 Google 和 Facebook 的面试邀请,就如实填写了。回复第二天后就收到了邮件通知,告诉我会有 HR 进一步跟进。第三天有一位 HR 联系我和我约电面的时间。微软约电面的方式和其他公司不大一样,HR 会给出很多个选项,让你在里面选择几个空闲的时间。另外值得一提的是这些时间都转成北京时间了,这也是微软在安排面试时比较人性化的一个地方。

第一轮面试是 HR 面。HR 先问了一些技术无关的问题,比如喜欢做什么,工作地点的偏好,什么时候开始学的编程,为什么投了微软等等。接着是一些智力题,比如 9 个小球,8 个质量相等,另一个比其他的重,如何用天平称两次把它找出来;公司开发了一种新键盘,有哪些测试它的方法;在会议室内怎么估计室外的温度。都是些更像是考验英语水平而不是技术能力的问题。

面完第二天收到了 onsite 的通知。虽然是北美的职位,onsite 面试地点却是在上海。我参加的是周日的面试,和我一起参加面试的还有一位学生,他之前在微软实习,了解到这次有去北美工作的机会后也想尝试下。面试官是从总部飞过来的工程师,一共有四位,其中三位都已经是 principal 级的了。HR 提到一般技术面试要五轮,因为我们之前参加过一轮笔试,所以只需要面四轮。

onsite 面每一轮的过程都差不多,都是面试官自我介绍,接着我介绍自己和做过的一些项目,然后开始技术问题,最后是我提问的环节。微软的面试问题会考察面试者编码、设计和测试三方面的能力。

coding 环节要求直接在白板上写代码,我被问到两个 coding 问题。一是如何检查一棵二叉搜索树是否正确,二是写一个解数独的程序。第一个问题写起来很快,第二个问题因为时间有限,我先写了一个没啥剪枝的暴力搜索的版本,写完后和面试官分析了可以在此之上做的优化。

设计方面的问题有两个。第一个问题是设计一个分布式的数据管理系统。使用场景可以是一个连锁店信息的记录系统,每个分店都有可能更新自己的信息,并把这些改动传播到整个系统中。在设计这一系统的同时要考虑性能、容错、一致性等要求。我一开始想了一个基于 push 的机制,在面试官指点下逐步优化,最后还是有不少问题。于是干脆重新设计了一个基于 poll 的系统,优化改进之后面试官满意了。

另一个设计问题和类的设计有关,要求设计一个包含图形界面的棋盘游戏。因为之前做过不少相关的开发,所以这一部分我还挺擅长的。按照 Single Responsibility 的原则设计了几个分工明确的类,另外把网络对战和 AI 接口都考虑进去了。设计完成后面试官要求我从用户鼠标单击这一事件开始介绍整个控制流程,在某些类中还会问及这么设计的原因,以及和其他设计方案相比的优缺点。

测试部分的问题也有两个。第一个问题是如何测试一个随机函数。第二个问题和分布式系统有关,面试官先向我介绍了一个分布式系统,包括它的使用场景和基本的架构,然后问我其中某一个部件应该如何测试。提到正确性、可伸缩性、一致性和容错性后再给出相应的测试方法应该差不多了。

onsite 面试后的第二天后就收到了 HR 的邮件,祝贺我拿到了 offer,并和我约时间谈具体的 offer 细节。虽然微软一开始拖了两个多月才开始安排面试,但是一旦开始面试后他家的效率非常高,是这次面试的几家公司里效率最高的了。

Google

Google 面试也是托学长推荐了。HR 说我的简历看起来很不错,先给我安排了两轮电面。

电面都和 coding 有关,面试官会给你一个 Google Docs 链接,在电话里描述题目后要求你在 Google Docs 上写程序。题目的难度不高,两轮一共四题,都是对基本数据结构的操作,例如给在一个未排序的数组中去掉重复的数字,还有把一个有序数组转成一个平衡二叉搜索树,在一个已排序但有重复数字的数组中查找元素等。

第一轮电面聊天的时候还发现第一轮的面试官是在 ITA Software 做的。正好前几天用他们的产品 Matrix Airfare Search 订到了低价的去土耳其的机票,过了一星期神奇的在面试的时候碰到了这个团队的工程师。当时一下子就兴奋起来,聊了不少和 Matrix 的有关的话题。这位面试官听说中国的机票也能用他们的平台查询,还挺吃惊的。他还提到他们原本想把计算任务放到 Google 内部的计算框架上,但是由于和合作方的合同的限制,没法把一些商业数据放到 Google 的平台里,只能继续用原有的计算引擎。

第二轮电面的面试官是位印度人,虽然我很难听懂他的口音,但是他很耐心,会和我重复描述问题,所以题目做下来也没啥困难。在和他的聊天中得知他除了正业(Youtube)外还在闲余时间研究机器人。

电面结束后第二天收到了 HR 的邮件,邀请我去总部面试。由于当时已经是九月底了,而我十月初打算去土耳其玩两星期,于是只能从土耳其回来后开始准备签证了。Google 的 HR 非常热情,每次回邮件都很及时,经常能在加州时间晚上十一点左右收到她的邮件。她帮我弄来了 Google 的面试邀请信,顺利的过了签证面试。之后另一位 HR 还帮我订好了从上海往返 San Jose 机场的机票,以及三晚的住宿(因为考虑到我需要倒时差,多了一晚住宿,这一点也很体贴)。

Google 给我安排的住宿是 Wild Palms Hotel,在 Sunnyvale。不愧是硅谷的旅馆,每天早上起来吃旅馆的早饭,都能听到有人讨论 Java。在 Sunnyvale 的第二天我坐公共汽车到处逛了逛,考虑到接下来要在加州玩一圈,就办了张 T-mobile 的一个月电话卡(60 美元,包括不限量的短信、通话和 3G 流量,但是这家的信号非常差)。这家旅馆和苹果总部也很近,出门有公交车直达,作为半个果粉自然不会浪费这个机会。

第三天在 Google 工作的学长开车带我去了公司。Google 的园区里有不少免费自行车,没有锁,直接就可以骑。我在 Google 商店买了点礼品,在园区骑车转了一会儿后就开始面试了。

面试一共有四轮,每轮 45-55 分钟,中间有 5 分钟的休息时间。中午会有 Google 工程师带你吃饭。带我吃饭的 Google 工程师也是中国人,了解到这点后我们就知道用中文聊天了。吃饭时间里了解了不少在 Google 工作的优缺点,也一定程度影响了我之后做的决定。

由于签了 NDA,没法在这里透露具体的面试题目。面试主要都是算法题,比电面难一点。除了算法题外我还被问到一个分布式系统的设计题,以及一个多线程相关的 coding 题,后者用信号量很容易解决。其实如果能和面试官好好交流,这些题目做出来应该是没啥问题的。

面完第二周 HR 通知我拿到 offer 了,打电话告之了 offer 的具体细节。Google offer 的邮件附件还包括一份各项福利的介绍,着实吸引人。我还记得 HR 打电话来的时候我正好在三藩 Exploratorium 边上的小湖旁,在湖边美景中听到这样的好消息自然分外兴奋。HR 还告诉我没有限制我的签约时间,可以在任意长的时间后再做出决定,也算是 Google 非常体贴的地方。另外具体的职位会在入职前一段时间决定,HR 的说法是可以根据自己的喜好在一些项目之中选择。

王远轩:北美求职记

Facebook

我在今年三月份投过一次 Facebook 的暑期实习,被告之已经招满了,接下来校招时会再联系我。七月份的时候我又在网站上投了一次开发职位,还麻烦一位在里面实习的学长帮我内推了。八月一位 HR 联系我安排第一轮面试,电面安排在了九月。

Facebook 的 HR 也很负责,她在电面前几天打电话和我聊天,介绍 Facebook 的基本情况,以及面试流程。第一轮电面结束后的情况分三种,如果面试表现很不错,那就直接获得了 onsite 的机会;如果面试表现一般,面试官不确定要不要,就会再加面一轮;如果面试表现不好,就可能直接被刷了。除此之外 Facebook 的 HR 比较体贴的一点在于给中国人安排的第一轮面试官很有可能也是个中国人,降低了语言上出现问题的可能。

HR 的电话里还提到 Facebook 入职后有六星期的 bootcamp,可以熟悉各个项目和团队,具体的项目是 bootcamp 结束后自己选的。问了一下在那工作的朋友,做出的选择一般都会被满足,因为 bootcamper 的选择分布还算比较平均的。

Facebook 电面和 Google 差不多,是在 collabedit 上进行的。也是面试官在电话中口述题目,我在网站上写代码。老实说这个网站的体验不怎么样,面试过程中出现过几次我这边写的代码没在面试官那里出现的情况。好在面试官比较有经验,一发现有问题就会提醒我刷新页面。

第一轮电面我做了三个 coding 题,题目都不难,但是要求 bug free。电面的面试官抓 bug 的能力着实厉害,找出了两个我一开始没发现的 bug。好在他提示说有 bug 但没指出的情况下,我把它们都修正了。面试题目难度和 Google 的电面难度差不多,都是对数组、二叉树和字符串的基本操作。第一题是把一个字符串中的 %20 都转成空格,第二题是按层打印一棵二叉树,第三题是找出两个有序数组里不同的数字(类似求集合的异或)。程序正确后面试官还会问一些优化方面的问题,例如在不同的情形下应该使用哪一种算法。

面完后第二天收到 recruiter 的消息说我拿到 onsite 的资格了,具体的时间会在十一月通知我。

Facebook 给我安排的酒店是 Palo Alto 的 Sheraton。酒店门口停着不少出租车,面试那天的出租车司机还是用 Square 收的钱。我的面试正好赶上了他们的 University Day。这一天的安排是上午三轮面试,中午吃饭,下午逛一圈公司以及三场讲座。我的第三轮面试还出了点茬子,面试官一直没出现,HR 只能先带我去吃中饭。中饭结束后 HR 带着别人边逛公司边介绍,我只能继续我的第三轮面试了。

Facebook 校招时本科生和硕士生是统一级别的,面试只包括算法题,不会有设计题;而博士生则高一级,面试的时候还会有设计题。三轮 onsite 面试包括一轮 jedi 和两轮 ninja。jedi 面主要是让面试者介绍自己的项目经历,了解面试者的技术专长和偏好,不过面试官也让我做了一个简单的 coding 题。ninja 面各有两个 coding 题,题目难度都不大,和电面差不多。但是与电面不同的是,面试官会深入问一些细节的问题,例如代码里生成了多少个新的对象,有没有办法优化等,有一个问题还要求我用一种算法实现后,再用另一种完全不同的思路实现一次。(onsite 面试是签了 NDA 的,这里就不方便透露具体的题目了)

面试完之后有三个讲座,第一个讲座介绍了 Facebook 总体的工作环境。第二个分产品和后台两个讲座,同时进行所以只能选一个。我一开始选择了后台开发,不过当时突然对产品有了兴趣,就去听了产品的讲座。一位负责 Events 开发的工程师结合这个产品介绍了下 Facebook 内部产品开发的流程,例如新特性是怎么出来的,如何测试等。最后一个环节是几位刚从 bootcamp 毕业的员工和我们分享他们在 Facebook 中工作的感受。

University Day 结束后,参加活动的每位学生还收到一个包装精致的礼物。拆开来后是一块两面分别刻着「Move fast and break things」和「Proceed and be bold」的玻璃砖。我还是很喜欢这个礼物的,这也一定程度上影响了我最后的选择。

面试完第二天 HR 从我这里要了三位 reference,包括他们的职称和联系方式,接下来 HR 会联系他们询问我的情况。Facebook 的动作也很快,第二周就给我发了 offer。有意思的是,offer 邮件的 welcome package 最后一页建议面试者在入职前熟悉一下 Unix,还推荐了几篇文章和两本书。

Google 和 Facebook 的 onsite 是在同一星期面的,前后只隔了一天,收到 offer 的时间也只差了一天。package 方面, Facebook 比 Google 的要好不少,但是 Google 的 HR 说可以 match Facebook 的 offer。去之前我想过如果两个 offer 都拿到,那就去 Google。但是到了这两个公司,和几位面试官以及在里面工作的朋友深入聊天后,最终还是选择了 Facebook,因为它规模更小,应该能有更多的锻炼机会。

另外我了解到的 Google 和 Facebook 的面试流程都是先由各位面试官给你打分,例如分 strong hire / hire / weak no hire / strong no hire 四档(不一定完全一致,比如可能会多一档 neutral)。同时要写下关于你的面试情况的报告。再接着由 hiring committee 讨论要不要给你 offer,以及 package 如何。有亮点(某位面试官的 strong hire)很重要,一个 strong hire 和几个 weak no hire 会比平庸的清一色的 weak hire 好。

Hulu

Hulu 是这几个公司里唯一一个我没有找人内推而拿到面试机会的,也是面试体验最好的一个公司。Hulu 和 Twitter、Zynga、Foursquare 等公司一样,用了 jobvite 接受和追踪职位申请。因为是申请的第一家公司,我在申请 Hulu 时的 cover letter 写得很详细,针对职位需求上的每一条都写了我的相关工作经验,这也许是最后能拿到面试机会的原因吧。其他公司的 cover letter 都写得很简单,短短两段就结束了。

Hulu 的第一轮电面和其他公司的有些不同。45 分钟里要做四个题。面试官提前十分钟发了一封邮件给我,上面有两段代码。第一段代码是一个检查两个字符串是否是 anagram 的程序,写得很绕而且性能很差。面试官先问我这段代码的用途,然后问有什么方法优化,并要求我把代码写在 titanpad 上。接着他问了我第二段代码是做什么的。第二段代码也写得有点复杂,不过可以看出是一个检查有向图里面是否存在环的程序。

然后是设计题,要求设计一个 LRU Cache,只要说出接口、用到的数据结构和大致的算法就可以了,我想了个用一个 LinkedList 和一个 HashMap 的方案。

第四题还是代码题,写一个合并两个有序链表的程序。

面完后还有点时间,我们就聊了聊。面试官是在 Hulu 做支付的,主要用的语言是 Scala(Hulu 里面各个团队用的技术都很自由,可以选择自己喜欢的语言开发,Python Ruby C# Java 都有)。我当时正好在字节社做 iOS 上的应用内购验证,就问了他有没有处理黑卡坏账方面的经验。可惜 Hulu 在 iOS 上只有订阅方式的支付途径,没有 non-consumable product 的相关经验。

面完后 HR 给我安排了第二轮电面。面试官来自法国人,是 FFmpeg 的维护者之一。面试官看我简历上有星际比赛的奖项,还当过校队的队长,就和我聊起了星际2的平衡性。接着说到最近的虫群之心 beta,他觉得改动没有当年母巢之战的有意思,因为前期的改动不大。

聊了二十分钟的星际2后才切入正题,coding 题很简单,就是在一个数组里找出两个数,使得他们和为给定的数。写完这个最基本的版本后还有些别的变化,比如如果所有的数都是一定范围内的正整数,这时可以用一个数组统计每个数字的出现频率。

二面结束后等了三星期还没有消息,不知道是默拒了还是 HR 忘了。三星期后我又写了封信询问我的二面结果,HR 回信说欢迎我去他们公司 onsite 面,之前校招忙把我忘了。

Hulu 的总部在洛杉矶,Santa Monica 附近,离海滩只有几公里的路程。一进面试的会议室就看到白板上写着「Welcome Yuanxuan to Hulu」,一下子对这个公司充满了好感。

Hulu 的 onsite 面试题是面过的几家公司里最难的,一共有四轮。前三轮由来自内容团队、API 团队和架构团队的工程师面试,最后一轮的面试是 CTO 亲自面的。题目也是涵盖了算法、设计和实际的编码,有一轮的问题从设计一个分布式系统开始,讨论了这个系统的身份验证、数据分片、原子性、容错等问题的设计,考察了很多细节的地方,最后还让我写了 SQL,以及如何优化这些查询指令。不过我对 SQL 很不熟悉,每次用都要查手册,当时用了 ActiveRecord 的查询接口代替。

CTO 面完后 HR 进来问了我有没有其他公司的 offer,接着带我逛了一圈 Hulu 的工作场所。Hulu 总部只有 40 位左右的工程师,大家相互之间都很熟,气氛非常好,也比较自由。逛完后 CTO 带我出去买了杯咖啡,在回来的路上给我发了 offer。Hulu 的 package 和 Facebook 的在数额上差不多,但是因为公司性质的问题没法发股票给我,只能用相近的奖金代替。

回到公司后,CTO 问我对哪个团队比较有兴趣,我说如果我最后签了 Hulu 的话应该会想去做后端。HR 就安排了这个团队的工程师和我一起出去吃晚饭,还给了我两张 voucher 用于支付回去的出租车。当时因为觉得去 Hulu 可能性不大,觉得对方这么热情实在不好意思,可是还是推脱不掉,只得跟着他们去了附近一家餐厅。因为 Hulu 主要内容是美剧和电影的,饭桌上讨论的主题也是各种电视剧,还提到接下来 Hulu 可能会搬到附近另一个办公楼。

最后还是没有接受 Hulu 的 offer,虽然对他家印象非常好。一方面我更希望在湾区工作,另一方面小公司吸引人的一个点在于初期的股票,由于 Hulu 没法发股票所以这个优势也就没了。

Twitter

Twitter 用的也是 jobvite 的招聘系统,我麻烦了一位在里面工作的学姐帮忙内推。据说 Twitter 相比其他互联网公司 work-life balance 是比较好的,工作会相对轻松。而在给我安排面试时 HR 给出的可以约的最晚的时间点,也是几个公司里最早的,于是我只能很早起床等待面试官的电话。

第一面是一位负责移动端网页前端开发的工程师面的。他说我的简历上工作经历很丰富,就不让我做 coding 题了,让我谈谈做过的这些项目。谈完项目后又进入了聊天时间,我提到喜欢 Twitter 的一个原因在于他有很多好用的开源项目。比如我平时写一些小型的 web 应用都会用 bootstrap,省时省力;而我之前实习的时候做的一个分布式的内容下载系统,也参考了 murder 的实现。另外因为当时我在实现字节社 iPhone 和 iPad 的 web 界面时碰到了之前修复的 bug 后来再次出现,忘了测试的情况,就问了他 Twitter 是怎么做移动端 web 界面的测试的。结果面试官说他们也基本上是买一堆设备然后人工测的,倒是桌面端可以用 Selenium

愉快的结束第一面后,就开始了略有点无语的二面。我的二面前三次都没面成,第一次被放鸽子了;第二次面试官是 iOS 团队的,听我介绍完自己想做后端时,说他面我不合适,会让 HR 再帮我重新安排一轮;第三次再次被放鸽子,面试官那天很忙,抽不出身。每次面试失败后都要再等一星期才能收到 HR 的消息,所以光二面就拖了一个月。

第四次二面终于面成了。我听面试官介绍应该是来自平台相关的团队,不过面试官接着问我是喜欢写代码还是喜欢倒腾环境的时候,我说喜欢写代码,结果面试官说他的团队主要是做运维的,开发的工作量很小。估计是考虑到之前已经放过一次鸽子了,这次面试官还是继续面下去了。

虽然运维团队本身不是我喜欢的,但是面试官的问题相当对我胃口。一上来就是一连串的几个关于僵尸进程的问题:什么是僵尸进程?如何列出所有的僵尸进程?如何获得这些僵尸进程的 PID?如何把它们终止?我用 ps grep awk xargs 配合管道把这几个问题用一行命令行解决了,他很满意。

第二问是统计一个 httpd 的访问日志中,访问量最大的前五个 IP。我用 Ruby 写了一个,六行代码就能搞定。

接着面试官了解 DNS 吗,如果浏览器没法上网一般怎么诊断?我的回答是先 dig 看 DNS 解析是否正确,然后用 ping 判断 IP 是否可以访问,再用 curl 看是不是浏览器设置的问题。最后还可以用类似 www.websitedown.info 的服务检查。

第四个问题是怎么把一个文件复制到多个机器上?我说可以先用 ssh-copy-id 把公钥拷过去,然后再用 scp 拷文件。面试官说这样机器多就麻烦了。我解释到可以用 expect 写脚本自动输入密码,还加了句当然也可以用 Twitter 的开源工具 murder 分布式部署。

第五问是文件系统中 soft link 和 hard link 的区别。我的解释是 soft link 是一种特殊的文件,它的内容是被指向的文件的路径,而 hard link 是直接指向 inode 的。所以 soft link 可以用于目录,但是 hard link 不可以。

文件系统中 inode 和 path 的区别。我回答是 inode 是文件系统的一个数据结构,指向某个磁盘上的文件;而 path 是由多个 struct dentry 组成的,每个 dentry 描述了 inode 的父子关系。

最后一问是如何修改 DNS 服务器?我说可以修改 /etc/resolve.conf。

感觉 Twitter 的电面题会包含不少概念题,当然也有可能是运维团队的特点。几天后我收到 HR 的邮件,告诉我两位二面面试官都表示我对他们的团队不怎么感兴趣,而除了这两个团队外目前还没有其他团队可以给我安排面试。估计从此就进入等待列表了,没能去总部 onsite 面试,我在签掉 Facebook 后就联系 HR 把招聘进程终止了。

后记

最后签了 Facebook,等着下一步关于工作签证手续的通知。mm 也表示愿意和我一起去美国,她应该会先在那里读个硕士再找工作。

希望接下来的签证手续等事情都一切顺利了。

3 收藏 8 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部