在O(n)时间和O(1)空间中将数组{a1,a2,....,an,b1,b2,...,bn}交织到{a1,b1,a2,b2,a3,b3}

时间:2020-01-04 15:20:28

标签: arrays algorithm

我必须插入给定格式的数组

{a1,a2,....,an,b1,b2,...,bn} 

{a1,b1,a2,b2,a3,b3} 

在O(n)时间和O(1)空间中。

示例:

Input - {1,2,3,4,5,6}
Output- {1,4,2,5,3,6}

这是按索引排列元素的顺序:

Initial Index    Final Index
 0                   0
 1                   2
 2                   4
 3                   1
 4                   3
 5                   5

通过观察一些例子,我发现ai (i<n/2) goes from index (i) to index (2i)bi (i>=n/2) goes from index (i) to index (((i-n/2)*2)+1)。您可以自己验证。如果我错了请纠正我。

但是,我无法在代码中正确应用此逻辑。

我的伪代码:

for (i = 0 ; i < n ; i++)
    if(i < n/2)
        swap(arr[i],arr[2*i]);
    else
        swap(arr[i],arr[((i-n/2)*2)+1]);

它不起作用。

我该如何编写算法来解决此问题?

4 个答案:

答案 0 :(得分:2)

元素bn已经在正确的位置,因此让我们忘记它,而只担心其他N = 2n-1个元素。注意,N总是奇数。

现在可以将问题重新声明为“将元素在每个位置i移到位置2i % N

位置0的项目不会移动,因此让我们从位置1开始。

如果从位置1开始并将其移至位置2%N,则在更换之前必须记住位置2%N处的物品。从位置2%N移到位置4%N,从位置4%N移到8%N,依此类推,直到返回位置1,您可以将剩余的物品放到剩下的插槽中

您保证 返回插槽1,因为N是奇数,并且乘以2 mod则奇数是可逆的。不过,您不能保证可以覆盖所有职位。整个排列将分成一些循环。

如果您可以从每个周期的一个元素开始此过程,那么您将完成全部工作。问题在于弄清楚哪些完成了,哪些没有完成,因此您不会两次覆盖任何周期。

我认为您不能以满足您的时间和空间限制的方式对任意N执行此操作...但是如果N = 2 x -1对于某些x,则出现此问题容易得多,因为每个周期正好包括某些位模式的循环移位。您可以在每个索引的恒定时间内为每个循环生成单个代表(称为循环领导)。 (我将在最后的附录中描述该过程)

现在,我们有了满足您约束条件的递归算法的基础。

给出[a1...an,b1...bn]

  1. 找到最大的 x ,使得2 x <= 2n

  2. 旋转中间元素以创建[a1...ax,b1...bx,ax+1...an,bx+1...bn]

  3. 使用上述过程以线性时间对数组的第一部分进行交织,因为它的模量为2 x -1

  4. 递归以交织数组的最后一部分。

由于我们保证要递归的数组的最后部分最大为原始大小的一半,因此对于时间复杂度,我们有这样的递归:

T(N) = O(N) + T(N/2)
     = O(N)

请注意,递归是一个尾调用,因此您可以在恒定空间中执行此操作。

附录:为班次生成2 x -1

Fredricksen和Kessler在名为“一种生成两种颜色的珠子项链的算法”的论文中给出了一种简单的算法。您可以在此处获取PDF:https://core.ac.uk/download/pdf/82148295.pdf

实现很容易。从x 0开始,然后重复:

  1. 将最低的0位设置为1。将其设置为 y
  2. 从顶部开始复制低序位
  3. 如果x-y除以x,则结果将成为循环先导
  4. 重复直到所有x 1次为止

例如,如果x = 8并且我们在10011111处,则最低的0是位5。我们将其切换为1,然后从顶部复制余数以得到10110110。虽然是8-5 = 3,而且3不能除以8,所以这个不是循环的领导者,我们继续下一个。

答案 1 :(得分:0)

我要提出的算法可能不是o(n)。 它不是基于交换元素,而是基于移动元素,如果您有列表而不是数组,则移动元素可能是O(1)。

给出2N个元素,在每次迭代(i)中,将元素置于N / 2 + i的位置,并将其移至位置2 * i

a1,a2,a3,...,an,b1,b2,b3,...,bn
   |            |
a1,b1,a2,a3,...,an,b2,b3,...,bn
         |         |
a1,b1,a2,b2,a3,...,an,b3,...,bn
               |      |
a1,b1,a2,b2,a3,b3,...,an,...,bn

以此类推。

N = 4的示例

1,2,3,4,5,6,7,8
1,5,2,3,4,6,7,8
1,5,2,6,3,4,7,8
1,5,2,6,3,7,4,8

答案 2 :(得分:0)

一个有点复杂的想法是假设每个位置都具有以下值:

1, 3, 5, ..., 2n-1 | 2, 4, 6, ..., 2n
a1,a2, ..., an | b1, b2, ..., bn 

然后使用O(n)的{​​{3}}中所述的两个排序数组的内联合并时间O(1)的空间复杂度。但是,我们需要在此过程中管理此索引。

答案 3 :(得分:0)

有一个实用的线性时间*就地算法in this question。包括伪代码和C代码。

<块引用>

它涉及将前 1/2 项交换到正确的位置,然后对移动的 1/4 项进行排列,然后对剩余的 1/2 数组重复此操作。

<块引用>

解读排列使用了这样一个事实,即左侧项目以交替的“添加到末尾,交换最旧”模式移动到右侧。我们可以用这个规则在这个排列中找到第 i 个索引:

<块引用> <块引用>

即使是 i,也到了 i/2。
对于奇数 i,在步骤 (i-1)/2 处将最旧的添加到末尾

*数据移动的次数肯定是O(N)。题问解扰指数计算的时间复杂度。我相信它不比O(lg lg N)差。