面试测试 - 重新排列阵列

时间:2011-11-12 17:54:10

标签: arrays algorithm

  

可能重复:
  Reordering of array elements

在给定的元素数组中,如[a1,a2,a3,.. an,b1,b2,b3,... bn,c1,c2,c3,... cn]编写一个程序来合并它们,如[a1 ,B1,C1,A2,B2,C2,...一,BN,CN]。 我们必须在O(1)额外空间中进行。

示例测试用例:

Input #00:

{1,2,3,4,5,6,7,8,9,10,11,12}

Output #00:

{1,5,9,2,6,10,3,7,11,4,8,12}

Explanation:

Here as you can notice, the array is of the form
{a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4} 

编辑: 我在亚马逊布局测试中得到了它。已经尝试了很长时间了。 PLease提供伪代码。我尝试的是为第二个元素e找到新的位置p(第一个已经在正确的位置),在p处插入e并对位置p处的旧元素重复相同的操作。但这是在一个周期结束。 我尝试检测循环并将起始位置递增1.但即使这样也不起作用。

EDIT2:

#include <iostream>
using namespace std;

int pos(int i, int n) 
{
    if(i<n)  
     {
         return  3*i;

           }

       else if(i>=n && i<2*n)
       {

            return 3*(i-n) + 1;
            }
    else if(i>=2*n && i<3*n)
       {
            return 3*(i-2*n) + 2;
            }
return -1;
}
void printn(int* A, int n)
{
         for(int i=0;i<3*n;i++)  
             cout << A[i]<<";";

    cout << endl;
     }

void merge(int A[], int n)
{
 int j=1;    
 int k =-1;
 int oldAj = A[1];
 int count = 0;
 int temp;
 while(count<3*n-1){

 printn(A,n);
 k = pos(j,n);
 temp = A[k];
 A[k] = oldAj;
 oldAj = temp;
 j = k;
 count++;
 if(j==1) {j++;}
}

 }

int main()
{
    int A[21] = {1,4,7,10,13,16,19,2,5,8,11,14,17,20,3,6,9,12,15,18,21};
    merge(A,7);

    cin.get();}

5 个答案:

答案 0 :(得分:10)

这就是所谓的就地in-shuffle算法,如果你想有效地完成它,这是一项非常艰巨的任务。我只是发布这个条目,所以人们不发布他们所谓的“解决方案”,声称它可以扩展到O(1)空间,没有任何证据......

如果列表的格式为a1 a2 a3 ... an b1 b2 b3 .. bn,则以下是一篇更简单的案例:

http://arxiv.org/PS_cache/arxiv/pdf/0805/0805.1598v1.pdf

答案 1 :(得分:4)

这里是对具有3个额外空间元素和O(n ^ 2)复杂度的算法的描述:

sasbsc分别是abc序列的下一个源索引。 d是复制目标索引。

在每一次迭代中:

  • sasbsc的元素复制到临时存储空间

  • 将数组元素向左移动以填充现在空置的索引sasbsc

  • 这会在d

  • 留下三个空位
  • 将三个元素从临时存储复制到空位。

示例(点表示&#34;空&#34;位置):

First iteration:
 copy to tmp: ., 2, 3, 4,  ., 6, 7, 8,   .,10,11,12
              1            5             9
 shift:       ., ., ., 2,  3, 4, 6, 7,   8,10,11,12
 copy to dst: 1, 5, 9, 2,  3, 4, 6, 7,   8,10,11,12

Second iteration:
copy to tmp: 1, 5, 9, .,   3, 4, ., 7,   8, .,11,12
                      2          6         10
shift:       1, 5, 9, .,   ., ., 3, 4,   7, 8,11,12
copy to dst: 1, 5, 9, 2,   6,10, 3, 4,   7, 8,11,12

Third iteration:
copy to tmp: 1, 5, 9, 2,   6,10, ., 4,   ., 8, .,12
                                 3       7    11 
shift:       1, 5, 9, 2,   6,10, ., .,   ., 4, 8,12
copy to dst: 1, 5, 9, 2,   6,10, 3,  7  11, 4, 8,12

修改

这是一个工作程序(它需要的不仅仅是口头描述:)))

#include <stdio.h>

#define N 4

int a[] = {1, 2,3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

void
rearrange ()
{
  int i;
  int d;
  int sa, sb, sc;
  int tmp [3];

  d = 0;
  sa = 0;
  sb = sa + N;
  sc = sb + N;

  while (sc < N*3)
    {
      /* Copy out.  */
      tmp [0] = a [sa];
      tmp [1] = a [sb];
      tmp [2] = a [sc];

      /* Shift  */
      for (i = sc; i > sb + 1; --i)
        a [i] = a [i - 1];

      for (i = sb + 1; i > sa + 2; --i)
        a [i] = a [i - 2];

      sa += 3;
      sb += 2;
      sc++;

      /* Copy in.  */
      a [d++] = tmp [0];
      a [d++] = tmp [1];
      a [d++] = tmp [2];
    }
}

int
main ()
{
  int i;
  rearrange ();

  for (i = 0; i < N*3; ++i)
    printf ("%d\n", a [i]);
  putchar ('\n');
  return 0;
}

似乎有效。 耸肩

答案 2 :(得分:3)

这是像你这样的问题的一般解决方案。

首先,对于每个源索引,您知道目标索引。现在,你这样:

  1. 拿第一个项目。找到它的最终位置。记住该地方的物品,并将第一个物品存放在那里。现在,找到记忆物品所属的地方,并将该物品放在那里,记住该被替换的物品。继续这个过程,直到它到达第一个项目的位置(显然)。
  2. 如果您已经更换了所有项目,那么您就完成了。如果没有,请取出第一个未转移的项目,然后从该项开始,继续重复步骤1中的步骤。
  3. 您需要标记已转移的项目。有不同的方法:例如,您可以使用项目存储中的一位。


    好的,上面的解决方案并不完全是O(1),因为它需要N个额外的位。下面是O(1)解决方案的概要,尽管效率较低:

    考虑项目a1,b1,c1。它们需要位于结果的前3个位置。所以我们正在做以下事情:记住a1,b1,c1,将这三个项目之外的数组压缩到后面(所以它看起来像这样:,,, a2,a3,...,an,b2,b3,.. 。,bn,c2,c3,...,cn),并将项目a1,b1,c1放在开头的位置。现在,我们找到了前3个项目的位置,因此继续执行a2,b2,c2等程序。

    编辑:
    让我们考虑上面大纲的时间复杂性。表示列表大小3*n。我们需要n步骤。列表的每个单独的紧凑化可以在一次通过中完成,因此是O(n)。步骤中的所有其他操作都是O(1),因此我们完全n * O(n) = O(n^2)复杂度。然而,这远非最佳解决方案,正如@yi_H所提到的,线性时间解决方案需要大量使用或多或少的高级数学。

答案 3 :(得分:1)

我找不到任何O(n)算法,但这是O(n ^ 2)就地一个,每次代码被给定输入测试时,我会将三元组移到最后一个,在C#中,可能是有缺陷的,如果是这样,请告诉我:

        int[] a = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
        int m = a.Length / 3;
        int firstB = a[m];

        for (int i = m-1; i > 0; i--)
        {
            int second = a[3 * m - 3];
            int third = a[3 * m - 2];
            //a[i + 2 * m] = a[i +2 * m];
            a[3 * m - 2] = a[2 * m - 1];
            a[3 * m - 3] = a[m - 1];
            for (int j = m - 1; j < 2 * m - 1; j++)
            {
                a[j] = a[j + 1];
            }
            for (int j = 2 * m - 2; j < 3 * m - 3; j++)
            {
                a[j] = a[j + 2];
            }
            a[3 * m - 5] = second;
            a[3 * m - 4] = third;
            m--;
        }
        a[1] = firstB;

答案 4 :(得分:-2)

这里有x * y数字:

a_11, a_12, ..., a_1x,
a_21, a_22, ..., a_2x,
...
a_y1, a_y2, ..., a_yx

然后数字a_ij在数组中包含索引i*x + j;

在你的程序之后,新索引将是

j * y + i

在你的采访中

{a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4} 

x为4,y为3,

所以使用索引“n”(

i = (n - (n % 4)) / 4;
j = n % 4;

现在您可以使用i, j, x, y计算新索引。

祝你好运。