【问题标题】:Give an O(N) algorithm to rearrange a list of true/false so that all false elements precede the true给出一个 O(N) 算法来重新排列真/假列表,以便所有假元素都在真元素之前
【发布时间】:2015-11-10 06:15:20
【问题描述】:

我有一个包含 N 个元素的数组,其中仅包含两个不同的键,true 和 false。我正在尝试编写一个 O(N) 算法来重新排列列表,以便所有虚假元素都在真实元素之前。该算法的一个具体要求是我只能遍历数组一次(这意味着我不能对数组进行两次遍历;一次计算真/假的数量,另一次将值分配给数组)。我也不允许创建外部临时数组。

最初我想使用计数排序,但意识到我不能这样做,因为这个赋值的要求是我不能创建一个外部/临时数组。

然后,由于只有两个可能的值,我想遍历一次并计算它们。然后第二次迭代并设置排序(进行排序)。但是,我也不能这样做,因为我只能进行一次迭代。

所以我自己尝试实现一种算法,该算法将只在数组中迭代一次并同时进行排序。到目前为止我想出的如下(这只是一个或多或少写成伪代码的想法)

array = T T T T F F F F
int len = length of array.
counter = 0
For item in array
    counter += 1
    If counter <= len/2
       if T change to F
    else
       if F change to T

当我完成这个时,我意识到这只有在所有 T 值都在数组的一侧,而所有 F 值都在另一侧时才有效。

我的问题是,谁能告诉我,我可以使用哪种 O(n) 排序算法对数组中的每个项目进行排序并排列它,以使所有虚假元素都在真实元素之前?

【问题讨论】:

  • 如果你从前面和后面同时迭代,在中间相遇时停止,这算作两次迭代吗?
  • 不,这不算作两次迭代。
  • 原本我想使用计数排序,但意识到我不能这样做,因为这个赋值的要求是我不能创建一个额外/临时数组。

标签: arrays algorithm sorting


【解决方案1】:

您可以尝试快速排序的想法:同时从头到尾遍历数组,并交换顺序不正确的元素。 IE。如果您在数组的左半部分找到true,请将其与右半部分的false 交换。

因为你只有 2 个不同的值,所以单次通过就足够了。

例子:

bool[] array = ...;
int low = 0;
int high = array.Length - 1;
do
{
    while (array[low] == false)
        low++;

    while (array[high] == true)
        high--;

    if (low <= high)
    {
        bool temp = array[low];
        array[low] = array[high];
        array[high] = temp;
    }
}
while (low < high);

这给了你精确的单程,即 O(N)。

【讨论】:

    【解决方案2】:

    保留一个索引 (lastFalseIdx) 在哪里插入 False 元素。所以,最初它是0。从左到右遍历数组,如果找到False,则将其与lastFalseIdx处的元素交换,并增加索引。

    Python(几乎是伪代码):

    arr = [True, True, False, False, False, True]
    
    print arr
    
    lastFalseIdx = 0
    
    for idx, val in enumerate(arr):
        if val == False:
            arr[lastFalseIdx], arr[idx] = arr[idx], arr[lastFalseIdx]   # swap elements
            lastFalseIdx = lastFalseIdx + 1
    
    print arr
    

    Demo

    【讨论】:

    • 你能用外行英语解释一下这段代码的作用吗?我只是想确保我遵循正确。
    【解决方案3】:

    这是一个在单独的数组中构造正确输出的部分解决方案。您可以通过观察初始化 output = input 时发生的情况来推断内联实现。

    #!/usr/bin/python
    
    input = [False, True, False, False, True, True, False, True, False]
    
    def sort2(input):
        i_false = 0
        i_true = len(input) - 1
    
        output = [None] * len(input)
        for (i, val) in enumerate(input):
            if val:
                output[i_true]  = True
                i_true -= 1
            else:
                output[i_false] = False
                i_false += 1
        return output
    
    print sort2(input)
    

    在通过数组单次前向传递后,您将获得所需的输出。

    【讨论】:

    • 我喜欢这个想法,但这是否将所有虚假元素都放在了前面?据我所知,这只会将 F 更改为 T 并将 T 更改为 F。
    • @OmarN:它不会改变任何东西,而是将值定位在输出数组中的正确位置。 Python 中的实现可能比文本描述更具可读性。
    【解决方案4】:

    简而言之:

    swap = 0
    for index in range(len(list)):
        if list[index] != true:
            list[index], list[swap] = list[swap], list[index]
            swap += 1
    

    【讨论】:

      【解决方案5】:

      希望以下答案对您有所帮助。

      internal void ArrangeBooleanArray()
          {
              bool[] inputArray = {false, true, true, false};
              int arrayLength = inputArray.Length;
              bool[] outputArray = new bool[arrayLength];
              int trueCount = 0;
              int falseCount = 0;            
      
              foreach (var item in inputArray)
              {
                  if (item == true)
                  {
                      trueCount++;
                      outputArray[arrayLength - trueCount] = item;                    
                  }
                  else
                  {
                      outputArray[falseCount] = item;
                      falseCount++;
                  }
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-19
        • 2020-05-10
        相关资源
        最近更新 更多