【问题标题】:How to merge two sorted array in o(1) space complexity? [duplicate]如何在 o(1) 空间复杂度中合并两个排序数组? [复制]
【发布时间】:2020-05-25 13:55:55
【问题描述】:

我有两个排序数组,我必须在不使用额外空间的情况下将两个排序数组合并为一个? 我正在检查this 解决方案,但我无法理解。

示例

Input: ar1[] = {10};
       ar2[] = {2, 3};
Output: ar1[] = {2}
        ar2[] = {3, 10}  

Input: ar1[] = {1, 5, 9, 10, 15, 20};
       ar2[] = {2, 3, 8, 13};
Output: ar1[] = {1, 2, 3, 5, 8, 9}
        ar2[] = {10, 13, 15, 20} 

【问题讨论】:

  • 您对解决方案有什么特别不了解的地方?
  • 看看std::merge
  • 好吧,示例“C++”解决方案是一个 C 解决方案。那种烂。
  • 如果是你不懂的逻辑/算法,应该去掉c++标签。如果它是“C++”解决方案的一部分,请显示相应的代码。
  • 老实说,我不明白为什么该算法有效。

标签: c arrays sorting


【解决方案1】:

这是一个简单的算法:

  • 虽然ar1 的最后一个元素大于ar2[0]
    • 交换它们。
    • ar1 的最后一个元素移动到ar1 中的位置,
    • ar2 的第一个元素移到ar2 中的位置,
    • 重复

空间复杂度O(1),时间复杂度O(n2)

【讨论】:

  • O(n2) 对这项任务来说太糟糕了。这个问题可以不用任何轮班来解决。这是合并排序算法的一部分。
  • 这是正确答案,强制他们列出所有要求!
  • @Skident:当然O(n2)不好,但是对O(1)空间复杂度的要求很高。有了 O(n) 额外空间,时间复杂度也下降到 O(n)
  • 有一个速度更快的算法,额外空间为 O(1),但它非常复杂。它涉及将数组划分为 sqrt(n) 段,使用第一个段作为缓冲区。参见研究论文:BC Huang, MA Langston, 1988 的“Practical in-place merging”。doi.org/10.1145/42392.42403
【解决方案2】:

我会针对“两个数组已经在一个缓冲区中”这种稍微简单的情况来解决它。

// requires: array is a pointer to a buffer of numbers,
// such that from [array, array+middle) is sorted, and [array+middle, array+length)
// is also sorted.
void merge_inplace( int* array, int length );

// This halves the number "gap", rounding up.  Unless the value was 1, in
// which case it returns 0.
int nextgap( int gap ) {
  if (gap==1) return 0;
  return (gap+1)/2;
}

void merge_inplace( int* array, int length ) {
  int gap = nextgap(length); // about half of length

  while (gap != 0)
  {
    int left = 0;
    int right = left+gap;
    while (right < length) {
      // ensure elements at left and right are in correct relative order:
      if (array[left] > array[right])
        std::swap(array[left], array[right]);
      // advance:
      ++left;
      ++right;
    }
    // repeat on a gap half-ish the size:
    gap = nextgap(gap);
  }
}

现在对两个不同的数组进行操作需要一些额外的工作/逻辑,但这主要是关于摆弄索引。

关键是,当您有两个已排序且彼此相邻的数组时,这种“合并远距离,然后更靠近在一起”算法的一次传递(它具有对数长度的子循环计数;所以 O(n lg n) 步骤) 足以对其进行排序。

【讨论】:

  • std::swap 是 c++,OP 将问题标记为c
  • @chqr OP 在我回答后编辑了解决方案以要求 C 小时。
【解决方案3】:

在您的示例中,数组被重新排序。这是你需要做的吗?

对于这个问题,你可以使用下一个算法:

  1. 使用for循环从0到array1的长度
  2. 比较array1array2 中的元素
  3. 如果array2 的一个元素小于array1 的一个元素,则交换它们
  4. 遍历 array2 以找到刚刚交换元素的更好位置

算法:

void reorder(std::vector<int>& arr1, std::vector<int>& arr2)
{
    for (size_t i = 0, j = 0; i < arr1.size(); )
    {
        if (arr1[i] < arr2[j])
        {
            i++;
            continue;
        }

        std::swap(arr1[i], arr2[j]);

        // find a better place for a swapped element in array 2
        for (size_t k = j, l = k+1; l < arr2.size(); k++, l++)
        {
            if (arr2[k] < arr2[l])
                break;
            std::swap(arr2[k], arr2[l]);
        }
    }
}

这个算法可以改进...

【讨论】:

  • 恐怕这不符合解释。
  • 好吧,是的,解决方案有点复杂,但是由于两个数组都是排序的,我们不需要 O(n2)
  • 您的答案中发布的代码具有 O(n2) 时间复杂度,即使两个数组都已排序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 2017-01-08
  • 1970-01-01
  • 2016-04-21
  • 2012-05-07
  • 1970-01-01
相关资源
最近更新 更多