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

17coding技术博客

共 5719字,需浏览 12分钟

 · 2020-12-31

阿里巴巴是目前全球最大的网上交易市场和商务交流社区,其地位是不可撼动的,没点真本事真的不容易进里面工作。今天所长在V2EX里看到有人吐槽阿里现在的面试这么难了吗?一起看看怎么个难法。


   //经过我的抽象大致是这样的,重量和数量问题不用考虑
   public static class Product{}
   public static class Package{}
   //此物品是否在包裹中
   public boolean productInPackage(Package packet, Product product) { ***** }

   //完成此方法: 每个背包可以有某些物品任意件,找出最少的背包包含所有的物品
   public Map findLeastPackages(List products, List packages) {}



 
 public static class Product{}
   public static class Package{}
   public boolean productInPackage(Package packet, Product product) {}

   // n 个背包, m 个物品, 每个背包可以有某些物品任意件, 找出最少的背包包含所有的物品  注: 此题一定有解
   //不考虑背包的权重、背包中物品权重、物品数量和重量
   public Map findLeastPackages(List products, List packages) {

       if (products == null || products.isEmpty() || packages == null || packages.isEmpty()) {
           return null;
       }

       Set productSet = new HashSet<>(products);
       Set packageSet = new HashSet<>(packages);

       int productsSize = productSet.size();
       int packagesSize = packageSet.size();

       //返回值
       Map priorityPackages = new HashMap<>(productsSize);

       //包裹 <=> 包裹里物品的双向对应
       //可以使用 Guava 的 Bimap
       Map> allPackages = new HashMap<>(packagesSize);
       Map, Package> productSetPackage = new HashMap<>(packagesSize);

       //寻找到包含数量物品种类最大的包裹
       Package maxProductsPackage = null;
       Set 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 maxProducts = allPackages.get(maxProductsPackage);
       Set secondMaxProducts = null;

       //删除最大包裹
       allPackages.remove(maxProductsPackage);

       //留下来的包裹 [不在最大包裹之内, 有差值, 但不是差值最大的]  找到差值最大的合并到 maxProducts, 然后转移到 mergeSets
       HashSet> remainSets = new HashSet<>(allPackages.values());

       //和最大包裹差值最大的, 已经合并到最大包裹内 [结果一定在这个里面]
       Set> mergeSets = new HashSet<>(packagesSize);
       mergeSets.add(maxProducts);

       while (maxProducts.size() != productsSize) {

           //如果 remainSets 为空,且 maxProducts.size() != productsSize 说明没有答案[不会发生]
           //可以把所有包裹相加去重后如果!= productsSize, 说明没有答案, 这样可以更快排除,这里只是以防万一
           if (remainSets.isEmpty()) {
               return null;
           }

           //寻找次大的包裹, 不需要比较优先级 [使用 iterator 模式删除元素, 优化循环]
           Iterator> iterator = remainSets.iterator();

           while (iterator.hasNext()) {

               Set 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;
   }


面试难不难,因人而异,因职位而异,因部门而异。想通过面试,能力当然不用说,综合素质也很重要,运气也占了一部分。



所长整理了一下关于算法面试的建议:

1.首先应抓紧时间仔细审题。

2.算法面试过程中交流很重要。算法面试中不要求“做完”,也不要求“最优解”,重要的是交流。与面试官确定题目信息,数据范围,阐述对题目的理解,以及准备使用的算法,思路要构建起来。

网友的建议:就算把下面这段话说给面试官听, 大概率也不会直接产生技术不错的印象。“我 JDK 重要源码学了一遍又一半,HotSpot 源码也有所涉猎,研究JDK 的BlockingQueue、ConcurrentLinkedQueue、WorkStealingQueue,JCtools 的 SPSC 、MPSC 、MPMC,Disruptor RingBuffer, 学习各种 lock-free 算法和结构,心想自己技术水平还算可以,没想到折戟在这里。”

3.“做完”,一般算法面试的代码量不会很大,如果能写出上百行,那么可能是做法有问题。不过由于题目不全,或许真就很复杂呢...

“最优解”,在无法一步到位的情况下,可以使用 brute force 。面试官会根据他对这个职位的期望,引导你寻找更优解,或者将最优解的算法作为你完成 brute force 之后的 follow up 。

4.临危不惧的心态。准备的正好不在面试官面的点上,不要着急,心态放好,继续加油。腹内有能力,胸中有乾坤,相信自己才能无畏艰难。


最后奉上一位大佬对面试的看法。




浏览 47
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报