在给定的元素数组中,如[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();}
答案 0 :(得分:10)
这就是所谓的就地in-shuffle算法,如果你想有效地完成它,这是一项非常艰巨的任务。我只是发布这个条目,所以人们不发布他们所谓的“解决方案”,声称它可以扩展到O(1)空间,没有任何证据......
如果列表的格式为a1 a2 a3 ... an b1 b2 b3 .. bn
,则以下是一篇更简单的案例:
答案 1 :(得分:4)
这里是对具有3个额外空间元素和O(n ^ 2)复杂度的算法的描述:
sa
,sb
,sc
分别是a
,b
和c
序列的下一个源索引。
d
是复制目标索引。
在每一次迭代中:
将sa
,sb
和sc
的元素复制到临时存储空间
将数组元素向左移动以填充现在空置的索引sa
,sb
和sc
这会在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)
这是像你这样的问题的一般解决方案。
首先,对于每个源索引,您知道目标索引。现在,你这样:
您需要标记已转移的项目。有不同的方法:例如,您可以使用项目存储中的一位。
好的,上面的解决方案并不完全是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
计算新索引。
祝你好运。