严格按O(n)时间对整数数组进行排序

时间:2015-03-21 15:19:09

标签: c# arrays

我最近在采访中被问到这个问题。

给定一个包含负数和正数的排序整数数组,如何根据元素的绝对值求助数组?

这必须严格按 O(n)时间进行。

  

输入

     

{ - 9,-7,-3,1,6,8,14}

     

输出

     

{1,-3,6,-7,8-,-9,14}

除了O(n)时间以外,有哪些可能的解决方案?

3 个答案:

答案 0 :(得分:12)

基本上,我们将有两个头,一个看着阵列的末端,一个在开头。

  v                   v
{-9, -7, -3, 1, 6, 8, 14}

我们比较我们的头指向的2个条目的绝对值,并将更大的值插入到我们新的排序数组中。所以这里将是14。

New array: {14}

然后我们移动我们选择的项目的头部靠近中心。所以在这里我们将头部指向14到8。

  v                v   
{-9, -7, -3, 1, 6, 8, 14}

然后我们重复这个过程,将2个绝对值中较大的一个插入到新的排序数组的开头。这里是-9,为| -9 | > | 8 |

New array: {-9, 14}

在我们再次移动头部之后:

      v            v        
{-9, -7, -3, 1, 6, 8, 14}

重复直到两个脑袋在中心相遇

答案 1 :(得分:2)

让我们举个例子:

{-9,-7,-3,1,6,8,14}

您可以将其重写为两部分:

{-9,-7,-3} and {1,6,8,14}

两个明显的观察结果:

  • 左侧部分按降序排列
  • 右侧部分按升序排列

现在你基本上只是合并这两个排序的子阵列,这可能是线性时间。在这里查看算法How to merge two sorted arrays into a sorted array?

由于您没有将这些阵列拆分,您会发现数组中的点向负数转为正数。从该分割点开始,您可以逐个索引,直到数组的边界,并再次重构排序的数组。

答案 2 :(得分:1)

如评论中所述,您基本上是在查看合并排序。原始数据已经排序,因此您所要做的就是从每组负数和正数中按顺序检索值,并根据它们的绝对值合并它们。

代码看起来像这样:

int[] input = { -9, -7, -3, 1, 6, 8, 14 };
int[] output = new int[input.Length];
int negativeIndex, positiveIndex = 0, outputIndex = 0;

while (input[positiveIndex] < 0)
{
    positiveIndex++;
}

negativeIndex = positiveIndex - 1;

while (outputIndex < output.Length)
{
    if (negativeIndex < 0)
    {
        output[outputIndex++] = input[positiveIndex++];
    }
    else if (positiveIndex >= input.Length)
    {
        output[outputIndex++] = input[negativeIndex--];
    }
    else
    {
        output[outputIndex++] = -input[negativeIndex] < input[positiveIndex] ?
          input[negativeIndex--] : input[positiveIndex++];
    }
}

以上是恕我直言,有点容易掌握,但正如另一个答案所指出的,你可以做到这一点,甚至没有扫描到数据的0点,从另一端排序。代码看起来像这样:

int[] output = new int[input.Length];
int negativeIndex =  0, positiveIndex = input.Length -1, outputIndex = input.Length - 1;

while (outputIndex >= 0)
{
    if (input[negativeIndex] >= 0)
    {
        output[outputIndex--] = input[positiveIndex--];
    }
    else if (input[positiveIndex] < 0)
    {
        output[outputIndex--] = input[negativeIndex++];
    }
    else
    {
        output[outputIndex--] = -input[negativeIndex] < input[positiveIndex] ?
            input[positiveIndex--] : input[negativeIndex++];
    }
}