【问题标题】:Traversing an array to find the second largest element in linear time遍历数组以在线性时间内找到第二大元素
【发布时间】:2011-04-12 06:19:43
【问题描述】:

有没有一种方法可以在线性时间内找到数组的第二大元素? 数组元素可以是正数、负数或零。 元素可以重复。 不允许使用 STL。 可以使用 Python。

解决方案:对数组进行排序并取第二个元素,但不允许排序

修改:根据定义,第二大元素将是数值较小的元素。就像我们有

Arr = {5,5,4,3,1} 然后第二大是4

加法 可以说,如果我想将问题推广到第 k 个最大且复杂度小于 nlogn 之类的线性问题,那么解决方案是什么。

【问题讨论】:

  • 为什么在线性时间可以在n long n 时间得到它?
  • 如果最大值重复,是否算作第二大值,还是我们选择它下面的那个?也就是说,在3,4,5,5 列表中,45 是第二大元素吗?
  • 4 被认为是第二大元素。
  • @user1344784 请建议如何在n logn 中完成,谢谢。
  • @Codeanu O(n) < O(n long n)

标签: c++ c algorithm


【解决方案1】:

遍历数组,保留 2 个内存槽来记录目前看到的最大的 2 个元素。返回两者中较小的一个。

....这个问题有什么我看不到的棘手之处吗?

【讨论】:

  • 如果这确实是和Simone相同的算法,如果前两项是相同的值和最大值,它也会失败。
  • 如果一个列表包含三个元素 {0, 1, 1},那么第二大元素是什么?仍然是 1。尝试对这样的列表进行排序,并从顶部取出第二个元素。
  • 我想这取决于第二大的定义。我添加了一条评论并删除了我的反对票。
  • @bdares 可以说如果我想将问题推广到第 k 大,这个算法可能不合适。
  • @Codeanu,那么是的,快速选择肯定是要走的路。但这不是你最初问的。当我看到这个问题时,我想到了快速选择和这种方法,但如果你真的只想要第二大(或大约),那么这比快速选择要简单得多。
【解决方案2】:

可以,这是伪算法:

max = 2max = SMALLEST_INT_VALUE;

for element in v:
   if element > max:
      2max = max;
      max = element;

  else if element > 2max:
      2max = element;

2max 是您要查找的值。

算法不会在特定情况下返回正确的值,例如元素相等的数组。

【讨论】:

  • 我认为您不需要交换... 2max = max 就足够了,因为您在下一行覆盖了 max 。另外,在第二行中,您假设 v[1]
  • 这个失败是前两个元素是相同的值和列表中的最大值。
  • 你是对的。 AFAICS,用可以预期的最小整数值初始化两者就足够了,不是吗?
【解决方案3】:

如果你想要一个真正的 O(n) 算法,并且想要在数组中找到第 n 个最大的元素,那么你应该使用 quickselect(它基本上是快速排序,你扔掉你不感兴趣的分区),下面是一篇很棒的文章,带有运行时分析:

http://pine.cs.yale.edu/pinewiki/QuickSelect

【讨论】:

  • @Codeanu : 很高兴你知道它对你有帮助
  • 答案中的链接似乎已损坏。这是关于快速选择算法的 wiki 文章:en.wikipedia.org/wiki/Quickselect
  • 另外,快速选择不是 O(n);它是 O(n^2),因为它在最坏情况下的性能很差。此外,它使用排序算法,但问题是不允许排序,所以这似乎违反了问题约束。
【解决方案4】:

伪代码:

int max[2] = { array[0], array[1] }

if(max[1] < max[0]) swap them

for (int i = 2; i < array.length(); i++) {
  if(array[i] >= max[0]) max[1] = max[0]; max[0] = array[i]
  else if(array[i] >= max[1]) max[1] = array[i];
}

现在,max 数组包含最多 2 个元素。

【讨论】:

  • 你没有检查 array[0] 和 array[1] 中哪个更大。
  • 泰勒克朗普顿,是的,你是对的。我忘了提那个。我马上就做!
【解决方案5】:
  • 创建一个大小为 3 的临时数组,
  • 在那里复制前 3 个元素,
  • 对临时数组进行排序,
  • 用源数组中的第 4 个元素替换临时数组中的最后一个元素,
  • 对临时数组进行排序,
  • 用源数组中的第 5 个元素替换临时数组中的最后一个元素,
  • 对临时数组进行排序,

对大小为 3 的数组进行排序是常数时间,您对源数组的每个元素执行一次,因此总体时间是线性的。

【讨论】:

  • 线性时间成本高,但确实是线性的。如果您要一直替换最后一项,您应该提到您希望按 descending 顺序排序。如果有重复的最大值(取决于重复是否计为最大值),这也会受到选择最大值的影响。
【解决方案6】:

是的。您将其标记为 C/C++,但您提到可以在 Python 中完成。无论如何,这是算法:

  1. 创建数组(显然)。
  2. 如果第一项大于第二项,则将第一个变量设置为第一项,将第二个变量设置为第二项。否则,反之亦然。
  3. 遍历所有项目(前两项除外)。
  4. 如果数组中的项大于第一个变量,则将第二个变量设置为第一个变量,将第一个变量设置为该项。否则,如果项目大于第二个变量,则将第二个变量设置为项目。

第二个变量是你的答案。

list = [-1,6,9,2,0,2,8,10,8,-10]

if list[0] > list[1]:
        first = list[0]
        second = list[1]
else:
        first = list[1]
        second = list[0]

for i in range(2, len(list)):
        if list[i] > first:
                first, second = list[i], first
        elif list[i] > second:
                second = list[i]

print("First:", first)
print("Second:", second)

【讨论】:

    【解决方案7】:
    // assuming that v is the array and length is its length
    int m1 = max(v[0], v[1]), m2 = min(v[0], v[1]);
    
    for (int i=2; i<length; i++) {
      if (likely(m2 >= v[i]))
        continue;
      if (unlikely(m1 < v[i]))
        m2 = m1, m1 = v[i];
      else
        m2 = v[i];
    }
    

    您需要的结果以 m2 为单位(出于性能目的,可能和不太可能将宏定义为 here,如果不需要它们,您可以简单地删除它们)。

    【讨论】:

      【解决方案8】:

      我认为其他答案没有考虑这样一个事实,即在像 [0, 1, 1] 这样的数组中,第二大是 0(根据更新的问题定义)。此外,所有提到的快速选择都不是 O(n) 而是 O(n^2),并且所做的工作比必要的要多得多(最重要的是问题陈述不允许的排序算法)。这是一个与 Simone 非常相似的算法,但经过更新以返回第二大唯一元素:

      def find_second(numbers):
          top = numbers[0]
          second = None
      
          for num in numbers[1:]:
              if second is None:
                  if num < top: second = num
                  elif num > top:
                      second = top
                      top = num
              else:
                  if num > second:
                      if num > top:
                          second = top
                          top = num
                      elif num < top: second = num
      
          if second is not None: return second
          return top
      
      if __name__ == '__main__':
          print "The second largest is %d" % find_second([1,2,3,4,4,5,5])
      

      【讨论】:

        【解决方案9】:
        // Second larger element and its position(s)
            int[] tab = { 12, 1, 21, 12, 8, 8, 1 };
            int[] tmp = Arrays.copyOf(tab, tab.length);
            int secMax = 0;
            Arrays.sort(tmp);
            secMax = tmp[tmp.length - 2];
            System.out.println(secMax);
            List<Integer> positions = new ArrayList<>();
            for (int i = 0; i < tab.length; i++) {
                if (tab[i] == secMax) {
                    positions.add(i);
                }
            }
            System.out.println(positions);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-10
          • 2016-03-19
          • 2018-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-14
          • 2017-06-01
          相关资源
          最近更新 更多