在不创建新列表的情况下以相同顺序打印列表的最大值

时间:2018-06-05 17:39:30

标签: python list dictionary

这里有一个清单

[9,1,2,11,8]

我需要打印此列表中的前3位,如

[9,11,8]

很容易排序并获取最高值并循环遍历同一个复制列表,以查找给定顺序中的最高值 但我不应该使用新列表来完成这项任务。 这可能吗?

5 个答案:

答案 0 :(得分:4)

def k_largest(iterable, k=3):
    it = iter(iterable)
    result = [next(it) for _ in range(k)] # O(k) space
    r_min = min(result)
    for elem in it:
        if elem > r_min:
            result.remove(r_min)  # O(n*k) time
            result.append(elem)
            r_min = min(result)
    return result

在平局的情况下,第一个值获胜。如果您希望获得最后一次胜利,只需将>更改为>=

这是大数据和小选择的好方法,即n>> k是n是输入的长度,k是选择的数字。  在这种情况下,k项是无关紧要的,因此该方法是 O(n)时间复杂度,有利于基于排序的方法的 O(n log n)。如果k很大,这将不再是一个好的解决方案。您应该查看维护已排序的结果集,将其平分为插入,并使用quickselect来查找最大值。

使用Python stdlib' s heapq.nlargest可以获得另一个具有更简单代码的选项,尽管它在实践中通常可能会更慢:

import heapq
from operator import itemgetter

def k_largest_heap(iterable, k=3):
    ks = heapq.nlargest(k, enumerate(iterable), key=itemgetter(1))
    return [k for i, k in sorted(ks)]

认为这是 O(n log(k)),虽然我确实在这里达到了我的知识边缘。

一些包含10,000个整数列表的时间:

from random import randint
nums =  [randint(1, 10000) for _ in range(10000)]
%timeit k_largest(nums)
# 331 µs ± 4.69 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit k_largest_heap(nums)
# 1.79 ms ± 27.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit top_three(nums)
# 1.39 ms ± 16.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

注意: top_three实施是用户Delirious Lettuce here的解决方案。

答案 1 :(得分:0)

我会修改select-sort以捕获(n)为MAX而不是一个。而不是运行n2,只需通过列表一次。

所以[9,1,2,11,8]

您使用MAX列表初始化[0,0,0] 然后循环通过你的列表采摘大于MAX的东西

  1. [9,0,0]
  2. [9,1,0]
  3. [9,1,2]
  4. [9,11,2]
  5. [9,11,8]
  6. 最棘手的部分是第4步,你需要决定保留9和2,并用11替换1。

答案 2 :(得分:0)

您还可以为列表实现包装类。拥有列表中最大值的私有数据成员(在您的情况下为3)。执行插入和删除后更新这些变量。

答案 3 :(得分:0)

我尝试根据您要求的输入和输出创建示例程序。我想过尝试一下。请随时优化或提供反馈。我试着解释代码本身的步骤。谢谢。

package com.test;

import java.util.ArrayList;
import java.util.List;

public class ArrangeList {
    public static void main(String[] args) {
        List<Integer> givenList = new ArrayList<>();
        givenList.add(9);
        givenList.add(1);
        givenList.add(2);
        givenList.add(11);
        givenList.add(8);

        int currentIndex = 0; //gives the current index
        while (givenList.size() != 3) {
            int nextIndex = currentIndex + 1; //gives you the next index 
            int currentValue = givenList.get(currentIndex); //gives you the current value for the current index 
            int nextValue = givenList.get(nextIndex); //gives you the next value for the next index

            if (nextValue < currentValue) { //check if the next value is greater than current value. If true, then remove the next value from the list
                givenList.remove(nextIndex);
            } else {
                currentIndex++; //increment the index if you if the current value is greater than the upcoming value from the list
            }

        }
        System.out.println(givenList); //prints the values stored in the list

    }
}

执行程序后的输出是:

[9, 11, 8]

答案 4 :(得分:-1)

编辑:

我很好奇我为什么被投票。 @wim的解决方案自愿忽略原始问题中关于&#34;的限制,而没有制作新的列表&#34;。唯一的反应是暂时将其改为一个双端队列,以奇怪的方式绕过该限制。目前,这是唯一符合所有OP要求的答案(下面列为两个单独的评论)。

  

以相同顺序打印列表的最大值而不创建新列表

     

我需要在此列表中打印前3位,如

此答案假定您需要按原始顺序提取的顶部数字的数量始终为3。如果是这种情况,则此答案似乎为O(n)时间和O(1)空格。

def top_three(nums):
    if len(nums) <= 3:
        return nums

    a = b = c = float('-inf')
    dex_a = dex_b = dex_c = None
    for i, num in enumerate(nums):
        if num > a and num > b and num > c:
            a, b, c = num, a, b
            dex_a, dex_b, dex_c = i, dex_a, dex_b
        elif num > b and num > c:
            b, c = num, b
            dex_b, dex_c = i, dex_b
        elif num > c:
            c = num
            dex_c = i

    if dex_a < dex_b < dex_c:
        print(a, b, c)
    elif dex_a < dex_c < dex_b:
        print(a, c, b)
    elif dex_b < dex_a < dex_c:
        print(b, a, c)
    elif dex_b < dex_c < dex_a:
        print(b, c, a)
    elif dex_c < dex_a < dex_b:
        print(c, a, b)
    elif dex_c < dex_b < dex_a:
        print(c, b, a)

试验:

In[3]: top_three([9, 1, 2, 11, 8])
9 11 8
In[4]: top_three([9, 1, 2, 11, 8, 9])
9 11 9
In[5]: top_three([3, 3, 1, 0, 4, 3, 2, 5])
3 4 5