• 请不要在回答技术问题时复制粘贴 AI 生成的内容
huang119412
V2EX  ›  程序员

阿里现在的面试这么难了吗?

  •  4
     
  •   huang119412 · Dec 25, 2020 · 26787 views
    This topic created in 1992 days ago, the information mentioned may be changed or developed.

    内推,二面面试官约了两天后要笔试(之前听说内推没有笔试),我不敢大意,想到工作三四年了,应该不会考察特别难的算法。查了一下别人分享的面试,要不是就是没有笔试, 要不是就是一些线性表,多线程顺序执行问题。我的算法基础还行,曾经也刷过题,线性表问题(比如反转链表,合并有序数组之类)、二叉树问题( BST 等)、排序算法( TopK,Nth 等等)、 手写 BlockingQueue 、LRU 、还是多线程问题,我觉得这些对我来说没什么问题。

    到了约定时间,面试官给我发了一个在线编程的网页,打开后题目已经在那里了,看起来是实际问题而不是具体的算法数据结构之类。面试官说给你 40 分钟,你把这两道题写完,我说能不能用 IDEA,面试官说不能,然后就不说话了。毫无代码提示补全,完全白板编程,不仅如此,题目描述都很简单,但是却有五六个类,之间都有关系,我抓紧认真审题,光弄懂题目都花了十多分钟,我吃惊的发现这两道题竟然都和动态规划有关,我当时心凉了一半。第一道题是用滑动窗口(双指针)找到极值,我用吃奶的力气才做完(白板编程,还有多层循环的 continue,break )。第二道题,经过我的抽象,发现竟然是一道复杂的背包问题。

    题目大致是 n 个背包,m 个物品, 每个背包可以有某些物品任意件, 找出最少的背包包含所有的物品。 注: 此题一定有解。

        //经过我的抽象大致是这样的,重量和数量问题不用考虑
        public static class Product{}
        public static class Package{}
        //此物品是否在包裹中
        public boolean productInPackage(Package packet, Product product) { ***** }
    
        //完成此方法: 每个背包可以有某些物品任意件,找出最少的背包包含所有的物品
        public Map<Product, Package> findLeastPackages(List<Product> products, List<Package> packages) {}
    

    心里真的拔凉拔凉的。时间到了我第二题只做到一半(找到了所有背包中所有的物品),后面时间不够,集合的交叉并补也记得不是很清楚了。而且只有大致的思路。也没想到最优的解法。

    我 JDK 重要源码学了一遍又一半,HotSpot 源码也有所涉猎,研究 JDK 的 BlockingQueue 、ConcurrentLinkedQueue 、WorkStealingQueue,JCtools 的 SPSC 、MPSC 、MPMC,Disruptor RingBuffer, 学习各种 lock-free 算法和结构,心想自己技术水平还算可以,没想到折戟在这里。

    不知道是不是内推的这个部门不招人( JD 描述还是 9 月份),自己一直对阿里有好感,但是一面面试官的傲慢,二面出这种题目白板编程,感觉自己被耍了。我只是面一个 P6 而已,现在也是公司的一个技术小 leader,每天 5 点多就能下班了,笔试晚上 9 点半还能听到对面的人在讨论需求。说实话这些对我有影响,但不是最重要的,我想去阿里因为我对自己和技术还有追求。当然最想去阿里中间件团队,但是据说特别难,所以选择了曲线救国的方法。可是遭遇这一遭。

    自己的解法,笔试结束后用 IDEA 花了近 2 个小时才写完,又花了一些时间优化了代码,但是不知道还有什么简单或最优的解法。

    
        public static class Product{}
        public static class Package{}
        public boolean productInPackage(Package packet, Product product) {}
    
        // n 个背包, m 个物品, 每个背包可以有某些物品任意件, 找出最少的背包包含所有的物品  注: 此题一定有解
        //不考虑背包的权重、背包中物品权重、物品数量和重量
        public Map<Product, Package> findLeastPackages(List<Product> products, List<Package> packages) {
    
            if (products == null || products.isEmpty() || packages == null || packages.isEmpty()) {
                return null;
            }
    
            Set<Product> productSet = new HashSet<>(products);
            Set<Package> packageSet = new HashSet<>(packages);
    
            int productsSize = productSet.size();
            int packagesSize = packageSet.size();
    
            //返回值
            Map<Product, Package> priorityPackages = new HashMap<>(productsSize);
    
            //包裹 <=> 包裹里物品的双向对应
            //可以使用 Guava 的 Bimap
            Map<Package, Set<Product>> allPackages = new HashMap<>(packagesSize);
            Map<Set<Product>, Package> productSetPackage = new HashMap<>(packagesSize);
    
            //寻找到包含数量物品种类最大的包裹
            Package maxProductsPackage = null;
            Set<Product> productTempSet = null;
    
            for (Package aPackage : packageSet) {
    
                if (aPackage == null) {
                    continue;
                }
    
                //初始化 aPackage
                allPackages.put(aPackage, (productTempSet = new HashSet<>()));
                productSetPackage.put(productTempSet, aPackage);
    
                for (Product product : productSet) {
                    if (product == null) {
                        continue;
                    }
    
                    //物品在背包中, 放入背包
                    if (productInPackage(aPackage, product)) {
                        allPackages.get(aPackage).add(product);
                    }
                }
    
                if (maxProductsPackage == null) {
                    maxProductsPackage = aPackage;
                } else {
                    maxProductsPackage = allPackages.get(aPackage).size() >= allPackages.get(maxProductsPackage).size() ? aPackage : maxProductsPackage;
                }
            }
    
            //已经找到背包有哪些物品
            //开始集合运算
    
            //maxProductsPackage 种类最多, 说明这个一定是最优里面的
            //maxProductsPackage 包含所有种类 直接返回
            if (allPackages.get(maxProductsPackage).size() == productSet.size()) {
                for (Product product : productSet) {
                    priorityPackages.put(product, maxProductsPackage);
                }
    
                return priorityPackages;
            }
    
            //todo 机试的就写道这里  主要记不太清楚集合的交叉并补 API,时间也不足  (40 分钟白板写代码)
            //没有使用 lambda 、Stream API 主要是记忆问题(白板写代码), 还有通过数组包装局部变量, 还有多层循环 break
    
    
            // 1.删除 maxProductsPackage 子集的包裹
            // 2.找到其他包裹和 maxProductsPackage 差值最大的包裹, 并取并集作为新的 maxProductsPackage
            // 3.判断 maxProductsPackage 是否包含所有物品, 是的话返回, 不是的话重复第一步直到找到结果或集合为空(一定有答案)
    
            Set<Product> maxProducts = allPackages.get(maxProductsPackage);
            Set<Product> secondMaxProducts = null;
    
            //删除最大包裹
            allPackages.remove(maxProductsPackage);
    
            //留下来的包裹 [不在最大包裹之内, 有差值, 但不是差值最大的]  找到差值最大的合并到 maxProducts, 然后转移到 mergeSets
            HashSet<Set<Product>> remainSets = new HashSet<>(allPackages.values());
    
            //和最大包裹差值最大的, 已经合并到最大包裹内 [结果一定在这个里面]
            Set<Set<Product>> mergeSets = new HashSet<>(packagesSize);
            mergeSets.add(maxProducts);
    
            while (maxProducts.size() != productsSize) {
    
                //如果 remainSets 为空,且 maxProducts.size() != productsSize 说明没有答案[不会发生]
                //可以把所有包裹相加去重后如果!= productsSize, 说明没有答案, 这样可以更快排除,这里只是以防万一
                if (remainSets.isEmpty()) {
                    return null;
                }
    
                //寻找次大的包裹, 不需要比较优先级 [使用 iterator 模式删除元素, 优化循环]
                Iterator<Set<Product>> iterator = remainSets.iterator();
    
                while (iterator.hasNext()) {
    
                    Set<Product> next = iterator.next();
                    next.removeAll(maxProducts);
    
                    //是 maxProducts 的子集
                    if (next.isEmpty()) {
                        iterator.remove();
                        continue;
                    }
    
                    //初始化 secondMaxProducts    可以删除次大元素减小集合
                    if (secondMaxProducts == null) {
                        secondMaxProducts = next;
                    } else {
                        secondMaxProducts = next.size() > secondMaxProducts.size() ? next : secondMaxProducts;
                    }
                }
    
                // 已经找完,退出循环
                if (secondMaxProducts == null || secondMaxProducts.size() == 0) {
                    break;
                }
    
                // 把 secondMaxProducts 加入到 maxProducts
                ////更新 maxProducts
                maxProducts.addAll(secondMaxProducts);
    
                //更新 mergeSets
                mergeSets.add(secondMaxProducts);
    
                //删除此元素
                remainSets.remove(secondMaxProducts);
                secondMaxProducts = null;
            }
    
            //mergeSets 即为所求
            mergeSets.forEach(set -> set.forEach(product -> priorityPackages.put(product, productSetPackage.get(set))));
            return priorityPackages;
        }
    
    116 replies    2020-12-28 15:51:58 +08:00
    1  2  
    yanhh
        101
    yanhh  
       Dec 26, 2020   ❤️ 2
    求职者太多,所以就出现了算法、白板编程这种没有意义的面试。楼上说的对,以后大家都把算法、白板编程搞好了,说不定就问你数学了,哈哈!行业问题。
    birdkyle79
        102
    birdkyle79  
       Dec 26, 2020
    实际上就是 HC 没了
    qingmuhy0
        103
    qingmuhy0  
       Dec 26, 2020
    还是学生,多关注关注大佬们的就业动态。
    jsondog
        104
    jsondog  
       Dec 26, 2020
    主要是人太多了。。。。
    mikulch
        105
    mikulch  
       Dec 26, 2020 via iPhone
    @leoli 工作 9 年了,哭出了声
    atonku
        106
    atonku  
       Dec 26, 2020   ❤️ 4
    大厂是好,但是不进大厂不是就一定不好。按您现在的工作情况,完全可以在业余时间继续学习,毕竟您已经是一个大佬了,到时候等 BAT 垮了,您就是下一个马云了。另外别跟面试官较劲,没准他女朋友刚跟别人跑了,老婆刚出轨了,或者突然发现自己是个太监呢,毕竟家家有本难念的经。
    zhangch1026
        107
    zhangch1026  
       Dec 26, 2020
    1 单听你的描述, 我不觉得面试官有傲慢的地方。
    LZ 心态适当放平和一点。就算面试官傲慢, 但是在面试过程中他也是有这个权利(比如看你面对压力和对方傲慢时候的反应)。
    2 题目本身不难, 都是必刷题。但 lz 如果之前没准备过,那 40 分钟白板估计是来不及写出来的。 当时但情况与其写到一半不如把伪码写出来,并且说清楚自己的思路。
    3 看的出来 lz 平时是热爱技术并且喜欢专研。 但是, 就算你把下面这段话说给面试官听, 大概率也不会直接产生你技术不错的印象。
    “我 JDK 重要源码学了一遍又一半,HotSpot 源码也有所涉猎,研究 JDK 的 BlockingQueue 、ConcurrentLinkedQueue 、WorkStealingQueue,JCtools 的 SPSC 、MPSC 、MPMC,Disruptor RingBuffer, 学习各种 lock-free 算法和结构,心想自己技术水平还算可以,没想到折戟在这里。”

    5 世界这么大, 又不是只有阿里,不是吗
    WNW
        108
    WNW  
       Dec 26, 2020   ❤️ 4
    在你问能不能用 IDE 的时候,这个面试官的回答已经很明显的告诉你他在把你当猴耍呢,很明显只要他不想让你通过就算你是 CTO 级别的他都能有 100 种方法让你通不过笔试!遇到这种情况最好的回应方式是直接掉头就走!阿里这公司的价值观就算你通过了进去也是给你整福报洗脑!
    Oysmart
        109
    Oysmart  
       Dec 26, 2020
    对阿里居然有好感。
    zkywalker
        110
    zkywalker  
       Dec 26, 2020   ❤️ 1
    @lewis89 啊,惭愧我刚面过阿里,到谈薪资了。一道算法没问,估计跟岗位也有关系,客户端 p6-p7 的岗位。
    0xDatou
        111
    0xDatou  
       Dec 26, 2020
    @zkywalker iOS 还是 Android ?
    ErwinCheung
        112
    ErwinCheung  
       Dec 27, 2020   ❤️ 1
    另外别跟面试官较劲,没准他女朋友刚跟别人跑了,老婆刚出轨了,或者突然发现自己是个太监呢,毕竟家家有本难念的经。
    fcoolish
        113
    fcoolish  
       Dec 27, 2020
    阿里并没有多难,只是很多时候恶心人是有一套。
    考不考算法看组的,我以前面的时候有考和不考的。
    我三面的时候跟我说去了不涨薪,我直接说算了。 (技术面试都过了)
    还有 hr 以所谓的阿里味随便挂人也是恶心了不少人。
    zkywalker
        114
    zkywalker  
       Dec 28, 2020
    @0xDatou Android
    godgc
        115
    godgc  
       Dec 28, 2020
    其实看态度的话 真心感觉他们没有那么“迫切”的需要人
    LYEHIZRF
        116
    LYEHIZRF  
       Dec 28, 2020
    @Actrace 哈哈 白板解积分
    1  2  
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5536 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 367ms · UTC 07:28 · PVG 15:28 · LAX 00:28 · JFK 03:28
    ♥ Do have faith in what you're doing.