楼主: 美帝马甲
跳转到指定楼层
上一主题 下一主题
收起左侧

[数组] 返回第二大的元素index

 
🔗
owensy 2021-8-29 04:44:45 | 只看该作者
全局:
莫涯泉水 发表于 2021-8-27 07:27
先遍历一遍找到最大,再遍历一遍找到次大,这样O(N)。这样行么?

非常可。但是有的面试官就会非要你one-pass (无奈
回复

使用道具 举报

🔗
莫涯泉水 2021-8-29 05:06:09 | 只看该作者
全局:
owensy 发表于 2021-8-28 16:44
非常可。但是有的面试官就会非要你one-pass (无奈

我另一个回复放出了one pass的code,不过是想了一段时间才整出来的,放到面试场景下早因紧张而GG了ORZ……
回复

使用道具 举报

🔗
 楼主| 美帝马甲 2021-8-29 05:19:21 | 只看该作者
全局:
owensy 发表于 2021-8-28 13:44
非常可。但是有的面试官就会非要你one-pass (无奈

我被烙印要求one pass
回复

使用道具 举报

🔗
faren753 2021-8-29 05:20:10 | 只看该作者
全局:
提供一个C++的解法。Input可以任意大小(比如stream),唯一要求是有足够内存来存output vector。
  1. #include <algorithm>  // std::sort
  2. #include <cmath>      // std::nan
  3. #include <utility>    // std::pair
  4. #include <vector>     // std::vector

  5. // Return the values and indexes of the top-k smallest/largest elements.
  6. std::vector<std::pair<double, size_t> > FindTopK(
  7.     const std::vector<double>& input, size_t k, bool is_largest, bool sorted) {
  8.   // Corner case, return empty vector.
  9.   if (k == 0) {
  10.     return std::vector<std::pair<double, size_t> >();
  11.   }

  12.   std::vector<std::pair<double, size_t> > result;
  13.   result.reserve(k);

  14.   // N iterations (N = input.size()), each iteration is O(k).
  15.   // Total complexity is O(kN). If k is constant, O(N).
  16.   for (size_t i = 0; i < input.size(); i++) {
  17.     double v1 = input[i];
  18.     if (result.size() < k) {
  19.       result.emplace_back(v1, i);
  20.     } else if (is_largest) {
  21.       // Find top-k largest
  22.       size_t min_index = 0;  // Local index
  23.       double min_value = result[0].first;
  24.       // Complexity of this loop is O(k)
  25.       for (size_t j = 1; j < k; j++) {
  26.         double v2 = result[j].first;
  27.         if (v2 < min_value) {
  28.           min_index = j;
  29.           min_value = v2;
  30.         }
  31.       }
  32.       // The new value is larger than the current smallest
  33.       if (v1 > min_value) {
  34.         result[min_index] = std::make_pair(v1, i);
  35.       }
  36.     } else {
  37.       // Find top-k smallest
  38.       size_t max_index = 0;  // Local index
  39.       double max_value = result[0].first;
  40.       // Complexity of this loop is O(k)
  41.       for (size_t j = 1; j < k; j++) {
  42.         double v2 = result[j].first;
  43.         if (v2 > max_value) {
  44.           max_index = j;
  45.           max_value = v2;
  46.         }
  47.       }
  48.       // The new value is smaller than the current largest
  49.       if (v1 < max_value) {
  50.         result[max_index] = std::make_pair(v1, i);
  51.       }
  52.     }
  53.   }
  54.   if (sorted) {
  55.     // Complexity of sorting is O(k log k).
  56.     if (is_largest) {
  57.       struct {
  58.         bool operator()(const std::pair<double, size_t>& a,
  59.                         const std::pair<double, size_t>& b) const {
  60.           return a.first > b.first;  // Descending order
  61.         }
  62.       } comparator;
  63.       std::sort(result.begin(), result.end(), comparator);
  64.     } else {
  65.       struct {
  66.         bool operator()(const std::pair<double, size_t>& a,
  67.                         const std::pair<double, size_t>& b) const {
  68.           return a.first < b.first;  // Ascending order
  69.         }
  70.       } comparator;
  71.       std::sort(result.begin(), result.end(), comparator);
  72.     }
  73.   }
  74.   return result;
  75. }

  76. // Return the k-th smallest/largest element and its index.
  77. // Total complexity O(kN + k). If k is constant, O(N).
  78. std::pair<double, size_t> FindKthTop(std::vector<double>& input, size_t k,
  79.                                      bool is_largest) {
  80.   // Corner case, return something representing invalid.
  81.   if (k == 0) {
  82.     return std::make_pair(std::nan(""), static_cast<size_t>(-1));
  83.   }

  84.   // O(kN)
  85.   std::vector<std::pair<double, size_t> > top_k =
  86.       FindTopK(input, k, is_largest, false);
  87.   // O(k)
  88.   if (is_largest) {
  89.     std::pair<double, size_t> max_pair = top_k[0];
  90.     for (size_t i = 1; i < k; i++) {
  91.       std::pair<double, size_t> p = top_k[i];
  92.       if (p.first > max_pair.first) {
  93.         max_pair = p;
  94.       }
  95.     }
  96.     return max_pair;
  97.   } else {
  98.     std::pair<double, size_t> min_pair = top_k[0];
  99.     for (size_t i = 1; i < k; i++) {
  100.       std::pair<double, size_t> p = top_k[i];
  101.       if (p.first < min_pair.first) {
  102.         min_pair = p;
  103.       }
  104.     }
  105.     return min_pair;
  106.   }
  107. }
复制代码
回复

使用道具 举报

🔗
faren753 2021-8-29 05:29:11 | 只看该作者
全局:

补充一点,这个解法逻辑上正确,写法上也基本没错,但是需要考虑两点,即Python里面 set 和 min()/max() 是如何 implement 的。

min()/max()的cost一般是O(N),linear search。set和dict有些不同。早期版本的CPython内部是用的hashtable,那么amortized cost是O(1),worst case cost是O(N)。如果implement as min/max heap,那么access cost是O(log N)。面试的时候如果碰见比较较真的面试官可能会问。
回复

使用道具 举报

全局:
darinyu 发表于 2021-08-28 11:54:31
这样不行吧

补充内容 (2021-08-29 03:03 +08:00):
堆保证
1 堆里的两个元素是数组到目前为止的最大的两个,其中堆底是最大,堆顶是次大
2 每一次扫描到新的元素e,只有当e>top是,pop并且把e入堆,这样继续保证新的top次大,新底最大
3 扫描完了把堆顶index输出就是

如果遇到多个相同,看题目要求怎么输出,如果要输出所有,那就拿一个hashmap保存次大的所有index
回复

使用道具 举报

全局:
易潇 发表于 2021-08-27 07:07:16
用2元素最小堆求的话时间复杂度是ON · logK。堆每次插入是logK,判断是否需要pop是1,pop+heapify也是logK
他现在的做法是o(kn)不是更慢..
回复

使用道具 举报

🔗
perseids 2021-8-29 07:17:15 | 只看该作者
全局:
Shubin_ren 发表于 2021-8-26 17:52
这个用一个两元素最小堆不是更简单…

用堆不值得, 能用简单数据结构解决的没必要用复杂数据结构, 有额外成本。
回复

使用道具 举报

🔗
perseids 2021-8-29 07:17:38 | 只看该作者
全局:
莫涯泉水 发表于 2021-8-27 07:27
先遍历一遍找到最大,再遍历一遍找到次大,这样O(N)。这样行么?

要求one pass
回复

使用道具 举报

🔗
柯基101 2021-8-29 07:31:07 | 只看该作者
全局:
perseids 发表于 2021-8-28 16:17
用堆不值得, 能用简单数据结构解决的没必要用复杂数据结构, 有额外成本。

简单数据结构的代价是效率和可读性,以及必要时候的followup
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表