跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 在微软做了四年面试官,分享一下刷 leetcode 的正确姿势
未分類
11 5 月 2020

在微软做了四年面试官,分享一下刷 leetcode 的正确姿势

在微软做了四年面试官,分享一下刷 leetcode 的正确姿势

資深大佬 : longSwordMan 13

在微软作了三四年的面试官,面过几百人,早已经知道现在的小朋友喜欢刷题,自然不会傻到原原本本的去考 leetcode 的原题。所以最好不要通过死记硬背,想要碰到原题来制霸面试。

划重点:编程面试,只有高频知识点,没有所谓的高频题。

众所周知,微软以及诸多其他大厂的面试算法题主要是以 leetcode 为素材的改编,我现在分享一些面试真题以及我自己和同事作为面试官的改编思路,希望可以帮到还在苦战刷题的同学。我会将大部分的 leetcode 原题过一遍,再附上面试真题的改写思路,尽量讲得傻瓜。由于篇幅限制,在这里我只举几个小栗子,更多面试真题和改写大家可以关注我的专栏文章。

我尽量保持每周两更+回复评论,看后续的反馈情况决定是否改变更新频率以及增减分享的内容,每条评论回复都会看,也可以加微信交流:longswordMAN,注明 V2EX 的 id 即可。

————————————————————————————————————————

废话不多说,正题开始:

我们先来看 leetcode 上第 1 号问题:Two Sum:

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9

所以返回 [0, 1]

大佬有話說 (47)

  • 主 資深大佬 : longSwordMan

    分析:简单题,考的是哈希表,暴力两重循环必挂。现在网上的帖子都喜欢和你说 leetcode 第 XX 题 是高频题,其实都是懒人思维,属于新手的思维误区。真正高频的是一些特定的知识点,如果按这种“原题照搬”思维,题目稍微做一些变招,大概率是要马失前蹄。

    这里的真正的高频考点是数据结构哈希表,划重点:哈希表的应用面试必考,一定会以某种形式在题目的某一部出现,以后还会讲到哈希表和二叉树,哈希表和二位数组等其他数据结构结合的变招。

  • 主 資深大佬 : longSwordMan

    面试官改编思路:
    1. 不同的运算规则,可以是乘除法,可以发明一个运算规则。
    真题:
    给定一个整数数组和一个目标值,找出数组中乘积为目标值的两个数。

    示例:

    给定 nums = [2, 7, 11, 15], target = 14

    因为 nums[0] * nums[1] = 2 * 7 = 14
    所以返回 [0, 1]

    其实换汤不换药,乘除法注意考虑边界情况即可(除以零),如果面试官自己发明的运算法:比如运算符:bla 的规则是: X ‘bla’ Y = X*Y – X -Y 。 同样的,查表规则改一下而已,换汤不换药,注意考虑边界情况 。

  • 主 資深大佬 : longSwordMan

    2. 换一个数据结构,看面试者是否能够利用规则,在时间复杂度上进一步优化。

    当然有序数组也可以改成二叉树等其他数据结构,或者是一些具备某特性的数据结构。有序数组的话,注意用二分查找,可以把时间复杂度降到 O ( logn ),注意哈希表的构建时间复杂度是 O ( n ),能直接用二分查找就直接用,不要考虑哈希。

    真题:

    给定一个“拐弯数组”,由两个有序数组拼接而成,但两数组升降序相反。 如:[1,2,3] + [6, 5, 4] —> [1,2,3, 6, 5,4]。 要求在拐弯数组中找到给定的 target 。

    这题如果用哈希,虽然是 O(n),但不是最优,没有用到数组的特性。我们先用二分法找到拐点,再到两个有序数组中二分,把复杂度优化到 O ( logn )

  • 主 資深大佬 : longSwordMan

    3. 变成多数之和,比如 3 sum 。这样的改写容易真题:
    给定一个有序整数数组和一个目标值,找出数组和为目标值的三个数。

    示例:

    给定 nums = [2, 7, 11, 15], target = 20

    因为 nums[0] + nums[1] + nums[2] = 2 + 7 + 11 = 20
    所以返回 [0, 1, 2]

  • 主 資深大佬 : longSwordMan

    思路类似,查两次表,但注意排除第一个数,比如 2+2+2 这种一个数重复用多次的情况。

    当然这都是容易的,如果三个数,再结合第 1 条变化,查表次数仍然是两次,但不要被复杂的运算搞晕,然后注意边界条件即可。

    看完了这几个我出的改编面试真题,不知道看官们是否对原来的刷题方式有所改观呢?总之,没有所谓的高频题,只有高频知识点,我们刷题的同时也要勤加思考,思考背后的考察知识点,甚至可以依照我上面分享的改编思路,自己给自己出题,这样才能把刷题的效率最大化。刚才说的三类变体,本质上都是对 [哈希表] 这个知识点的考察,如果对题目本身死记硬背,而忽视知识本身,是非常低效的。那么哈希表这个数据结构的意义就在于:可以通过 O ( 1 )的时间复杂度来查找元素是否存在于集合中,而不用 O ( n )来遍历查找。

    下次更新一些新的真题,着重说一些其他的哈希表的面试变招,会结合 leetcode 原题来说。

  • 資深大佬 : noreplay

    等更新,收藏了

  • 資深大佬 : GromHellscream

    谢谢分享,先收藏一波。

  • 資深大佬 : hdbzsgm

    是这个思路 我刷题喜欢 按模块来 链表 数组 哈希 树 图 然后再看看 字符串 greedy dp dfs bfs 类似变种的题就差不多了

  • 主 資深大佬 : longSwordMan

    @hdbzsgm 同路中人

  • 主 資深大佬 : longSwordMan

    @hdbzsgm 握爪

  • 資深大佬 : basefas

    所以说专栏呢?

  • 資深大佬 : also24

    @longSwordMan #3
    有序数组的话,可以直接双指针 O(n) 解决吧

    [ 1, 2, 3, 5, 8, 9 ], target = 8

    1+9 = 10 > 8
    1+8 = 9 > 8
    1+5 = 6 < 8
    2+5 = 7 < 8
    3+5 = 8

  • 資深大佬 : 27

    @also24 可以,但是也不如二分的 O(logn)快

  • 資深大佬 : also24

    @longSwordMan #3
    对于有序数组二分查找的方案,
    因为第一个数字还是要遍历的也就是 O(n) ,
    然后查询第二个数字的时候走二分查找需要 O(logn),
    所以实际上总体复杂度是 O(nlogn) 吧

  • 資深大佬 : also24

    @27 #13
    二分查找也需要遍历第一个数字的吧,还有个 O(n) 在外面哇

  • 資深大佬 : eastlhu

    期待大佬的专栏

  • 資深大佬 : WhyLevi

    干货拉满

  • 資深大佬 : xuzywozz

    多谢分享,收藏了

  • 資深大佬 : yamasa

    马克

  • 資深大佬 : yamasa

    收藏,后面学习

  • 資深大佬 : zhouwei520

    期待专栏文章

  • 資深大佬 : also24

    @basefas #11
    @eastlhu #16
    @zhouwei520 #21

    翻了下知乎,翻到了原回答和专栏地址:
    https://www.zhihu.com/question/32019460/answer/1268448274
    https://zhuanlan.zhihu.com/c_1253290991295655936

    BTW:看到原回答下面其实也在讨论二分查找解法实际上是 O(nlogn) 而不是 O(log) 的事儿

  • 資深大佬 : Jooooooooo

    好帖子

  • 資深大佬 : gzfrankie

    @also24 二分那道题是 O(logn)啊,那道题跟哈希是没关系的。

    这道题暴力解法就是 O(n),从头到尾扫一次,直到扫到 num[i-1]<num[i] && num[i+1]>num[i+2]成立,那么 num[i]就是拐点。所以如果你提供一个比 O(n)还要慢的方法,不是自作多情么…

    二分怎么做?起始范围选[0..n-1],i 定为中点(n-1)/2

    三个条件:
    1.若 num[i-1]<num[i] && num[i+1]>num[i+2]成立,那么 num[i]就是拐点
    2.若 num[i-1]<num[i] && num[i+1]<num[i+2],那么前半边的数可以舍弃,二分范围定为[(n-1)/2, n-1],继续二分
    3.若 num[i-1]>num[i] && num[i+1]>num[i+2],那么后半边的数可以舍弃,二分范围定为[0, (n-1)/2],继续二分

    因为每次二分都可以舍弃一半的数不用看,所以是 logn 。

    *以上伪代码简洁起见我没有考虑各种边界条件。

  • 主 資深大佬 : longSwordMan

    @also24 感谢搬运,给定有序数组,查找目标的情况下二分查找是 O(logn),如果超过 O ( n )没理由不用哈希

  • 主 資深大佬 : longSwordMan

    @gzfrankie 正解

  • 主 資深大佬 : longSwordMan

    晚些会拉群,加我的人太多操作不过来

  • 主 資深大佬 : longSwordMan

    @gzfrankie 征用一下哈,很多跟我帖的同学还是不懂

  • 資深大佬 : gzfrankie

    @longSwordMan 没问题的

  • 資深大佬 : angcz

    很棒啊 不过在论坛连载还是有很多不便之处 最好开个博客吧

  • 資深大佬 : also24

    @gzfrankie #24
    @longSwordMan #25
    我知道为什么会产生误解了,我们说的压根不是同一道题目。

    如下图所示,我其实针对的是黄色部分,我所说的题目是:
    按照 Two Sum 的题目规则,寻找和为 target 的两个数,但是将给定数组改成有序数组。
    针对黄色部分这道题,使用哈希解法和双指针解法的时间复杂度都为 O(n),二分查找的时间复杂度为 O(nlogn)。

    你们在说的是黄色部分的题目,即:
    针对 『拐弯数组』,寻找给定的 target 。
    针对蓝色部分这道题,使用哈希解法的时间复杂度是 O(n), 二分查找的时间复杂度为 O(logn)

    顺带提一句,蓝色部分这道题,其实非常接近 leetcode 上的 『山脉数组中查找目标值』这道题:
    https://leetcode-cn.com/problems/find-in-mountain-array/

    https://i.loli.net/2020/06/10/tVY6dhJgACaQbsP.png

  • 資深大佬 : also24

    修正 typo -> 你们在说的是蓝色部分的题目

  • 主 資深大佬 : longSwordMan

    @also24 是啊,所以第一题我没用二分查找啊,用了哈希,这不是整个帖子要表达的么?区别啥时候用哈希啥时候不用

  • 資深大佬 : also24

    @longSwordMan #33
    黄色部分是你在 3 发的前半部分,被误解成了在第一题的基础上替换为『有序数组』,其它条件不变。

    知乎上和你争吵的那位,也是这样理解了,所以才一直认定是 O(nlogn) 的复杂度。

  • 主 資深大佬 : longSwordMan

    @also24 是的,我其实已经在说第二题了,估计没转过来。。

  • 資深大佬 : also24

    @longSwordMan #35
    因为你后面在说 『改编思路』嘛,而且改编 1 、改编 3 都是确实和原题主体内容一致的。
    自然会觉得是改编 2 也是从原题上发展而来的。

    结果蓝色部分的改编 2,从题目内容角度来说,其实和 Two Sum 已经完全无关了。

  • 主 資深大佬 : longSwordMan

    @also24 是的,第一篇的改编不是太好,主要是希望从简单题入手。后续可以关注我该系列的第二,第三篇

  • 資深大佬 : also24

    @longSwordMan #37
    嗯,搞清楚问题是怎么出现的就好,这样才更有意义~
    还是要感谢分享~~

  • 資深大佬 : chendeshen

    这个适合开个微信群

  • 主 資深大佬 : longSwordMan

    @also24 是的,感谢指出缺点

  • 資深大佬 : ccvzz

    在地上也看到 lz 了,lz 为啥后来被禁言了[好奇]

  • 主 資深大佬 : longSwordMan

    @ccvzz 我也想知道。。。

  • 資深大佬 : shiji

    为什么我最近总看到这篇文章…

  • 資深大佬 : Ahian

    权威

  • 主 資深大佬 : longSwordMan

    @Ahian 过奖哈

  • 主 資深大佬 : longSwordMan

    我们接着再看一题,看一看怎么去用动态规划的思路来解题。

    给定整数数列 nums, 找到连续和最大的子数列,并返回数列和和,例:

    Input: [-2,1,-3,4,-1,2,1,-5,4],
    Output: 6

    其中[4,-1,2,1]加起来为 6 。

  • 主 資深大佬 : longSwordMan

    还是老套路,一个角标变两个角标而已,和上题一样,暴力两重循环必挂。那么正确的解法是怎样的呢?我们接下来说这道题背后考察的要点和面试官改编的思路。

    我估计不少人需要 O(n^3)才做得出来,如果我告诉你,这题的最优解法是 O(n),咋一看是不是不敢相信?我们要想不去暴力解,必须要头脑冷静分析,这个子数列的一些特征。作为面试官,如果这题面试者不假思索地写答案,如果还写对了,十有八九是背答案,依然是不给过。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具