在长度为n的列表中找到x个最小的整数

时间:2010-09-21 20:47:24

标签: algorithm

你有一个n个整数的列表,你想要x最小。例如,

x_smallest([1, 2, 5, 4, 3], 3)应该返回[1, 2, 3]

我将在合理范围内对独特的运行时进行投票,并将绿色检查提供给最佳运行时。

我将从O(n * x)开始:创建一个长度为x的数组。在列表中迭代x次,每次都拉出下一个最小的整数。

编辑

  • 你不知道这些数字有多大或多小。
  • 你不关心最终订单,你只想要x最小。
  • 这已经在某些解决方案中得到了解决,但是我们可以说,虽然您无法保证获得唯一列表,但您也不会获得简并列表,例如[1, 1, 1, 1, 1]

12 个答案:

答案 0 :(得分:13)

你可以在O(n)时间内找到第k个最小元素。 This has been discussed on StackOverflow before。有一些相对简单的随机算法,如QuickSelect,运行在O(n)预期时间和更复杂的算法,运行在O(n)最坏情况时间。

给定第k个最小元素,你可以在列表上进行一次传递,找到小于第k个最小值的所有元素,然后就完成了。 (我假设结果数组不需要排序。)

总运行时间为O(n)。

答案 1 :(得分:8)

在跳过列表中按排序顺序维护到目前为止最高的x列表。遍历数组。对于每个元素,找到它将在跳过列表中插入的位置(log x time)。如果在列表的内部,它是迄今为止最小的x之一,那么插入它并删除列表末尾的元素。否则什么都不做。

时间O(n * log(x))

替代实现:在最大堆中保持x最高集合,将每个新元素与堆的顶部元素进行比较,并且仅当新元素小于顶部元素时才弹出+插入新元素。由于与top元素的比较是O(1)和pop / insert O(log x),这也是O(nlog(x))

答案 2 :(得分:3)

将所有n个数字添加到堆中并删除其中的x个。复杂性为O((n + x) log n)。由于x显然小于n,因此它是O(n log n)

答案 3 :(得分:3)

如果已知数字范围(L),则可以进行修改后的计数排序。

given L, x, input[]
counts <- array[0..L]
for each number in input
    increment counts[number]
next

#populate the output
index <- 0
xIndex <- 0
while xIndex < x and index <= L
   if counts[index] > 0 then
       decrement counts[index]
       output[xIndex] = index
       increment xIndex
   else
       increment index
   end if
loop

这有一个O(n + L)的运行时间(内存开销为O(L)),如果范围很小(L

答案 4 :(得分:1)

def x_smallest(items, x):
    result = sorted(items[:x])
    for i in items[x:]:
        if i < result[-1]:
            result[-1] = i
            j = x - 1
            while j > 0 and result[j] < result[j-1]:
                result[j-1], result[j] = result[j], result[j-1]
                j -= 1
    return result

最坏情况是O(x * n),但通常更接近O(n)。

答案 5 :(得分:0)

Psudocode:

def x_smallest(array<int> arr, int limit)
    array<int> ret = new array[limit]

    ret = {INT_MAX}

    for i in arr
        for j in range(0..limit)
            if (i < ret[j])
                ret[j] = i
            endif
        endfor
    endfor

    return ret
enddef

答案 6 :(得分:0)

在伪代码中:

y = length of list / 2

if (x > y)
  iterate and pop off the (length - x) largest
else
  iterate and pop off the x smallest

O(n / 2 * x)?

答案 7 :(得分:0)

sort array
slice array 0 x

选择最佳排序算法,您就完成了:http://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms

答案 8 :(得分:0)

您可以排序然后获取前x个值吗?

使用QuickSort O(n log n)

Java:

import java.util.Arrays;
import java.util.Random;

public class Main {

    public static void main(String[] args) {
        Random random = new Random(); // Random number generator
        int[] list = new int[1000];
        int lenght = 3;

        // Initialize array with positive random values
        for (int i = 0; i < list.length; i++) {
            list[i] = Math.abs(random.nextInt());
        }

        // Solution
        int[] output = findSmallest(list, lenght);

        // Display Results
        for(int x : output)
            System.out.println(x);
    }

    private static int[] findSmallest(int[] list, int lenght) {
        // A tuned quicksort
        Arrays.sort(list);
        // Send back correct lenght
        return Arrays.copyOf(list, lenght);     
    }

}

非常快。

答案 9 :(得分:0)

    private static int[] x_smallest(int[] input, int x)
    {
        int[] output = new int[x];
        for (int i = 0; i < x; i++) { // O(x)
            output[i] = input[i];
        }

        for (int i = x; i < input.Length; i++) { // + O(n-x)
            int current = input[i];
            int temp;

            for (int j = 0; j < output.Length; j++) { // * O(x)
                if (current < output[j]) {
                    temp = output[j];
                    output[j] = current;
                    current = temp;
                } 
            }
        }

        return output;
    }

看看复杂性:     O(x +(n-x)* x) - 假设x是某个常数,O(n)

答案 10 :(得分:0)

使用splay tree怎么样?由于splay树采用自适应平衡的独特方法,因此可以实现算法的灵活实现,并且可以在以后按顺序枚举x项。这是一些伪代码。

public SplayTree GetSmallest(int[] array, int x)
{
  var tree = new SplayTree();
  for (int i = 0; i < array.Length; i++)
  {
    int max = tree.GetLargest();
    if (array[i] < max || tree.Count < x)
    {
      if (tree.Count >= x)
      {
        tree.Remove(max);
      }
      tree.Add(array[i]);
    }
  }
  return tree;
}

GetLargestRemove操作的摊销复杂度为O(log(n)),但由于最后访问的项目冒泡到顶部,因此通常为O(1)。因此空间复杂度为O(x),运行时复杂度为O(n * log(x))。如果数组恰好已经被排序,则该算法将使用升序或降序有序数组实现其O(n)的最佳情况复杂度。然而,非常奇怪或奇怪的排序可能导致O(n ^ 2)复杂度。您能猜出为了实现这一目标需要如何订购数组吗?

答案 11 :(得分:0)

在scala中,可能还有其他函数式语言,不用脑子:

scala> List (1, 3, 6, 4, 5, 1, 2, 9, 4)  sortWith ( _<_ ) take 5
res18: List[Int] = List(1, 1, 2, 3, 4)