您的位置:首页 > 其它

数组元素交叉排列的算法题(a1 a2 a3 .. an b1 b2 b3 .. bn -->a 1 b1, a2 b2, a3 b3, .. an bn )

2010-06-30 21:12 429 查看
题目:给定整数数组,元素为a1 a2 a3 .. an b1 b2 b3 .. bn元素个数为 2n

要求:请生成如下数组,a1 b1, a2 b2, a3 b3, .. an bn.

条件:时间复杂度为O(N),空间复杂度为O(1).

来源:http://topic.csdn.net/u/20100623/09/dd25166f-bac4-4b2d-98ab-71cab69f4241.html?54216

//***************************************************************************************

思路:

1、首先证明当 n=2^k 时,存在时间复杂度为O(N),空间复杂度为O(1)的算法。

2、其次证明对任意n,存在时间复杂度为O(N),空间复杂度为O(1)的算法。

证明:

1、当 n=2^k 时,存在时间复杂度为O(N),空间复杂度为O(1)的算法。

首先,从新编号,从“a1 a2 a3 .. an b1 b2 b3 .. bn” 到“0, 1, ... ,2^k-1, 2^k,... ,2^(k+1)-1”。

设某元素原来的下标为i,变换后的下标为j,则有:j=(2*i)%(2*n-1)。 例如:1-->2 (a2-->a3), 2-->4 (a3-->a5)。

然后,从1,3,..., n-1依次执行变换。例如n=8,则有:

1-->2-->4-->8-->1

3-->6-->12-->9-->3

5-->10-->5

7-->14-->13-->11-->7

设从i(i=2*k+1)开始变换的一组下标的集合为Si,则可以证明,Si∩Sj=空集,且 ∪Si=全集。

所以,该变换的时间复杂度为O(N),空间复杂度为O(1)的算法。

2、对任意n,存在时间复杂度为O(N),空间复杂度为O(1)的算法。

对任意n,有n=∑ck*x^k,其中ck=0或1。

因此,可以采用对任意ck=1的情况:

首先,做整体移位,两个2^k连续块放在一起(采用翻转法[1],时间复杂度为O(N),空间复杂度为O(1));

其次,对两个2^k连续块采用上面的算法;

然后,对剩余部分再采取前两步的方法,直到k=1。

例如n=11,则有:

第一次:

0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21

变为 0,1,2,3,4,5,6,7,11,12,13,14,15,16,17,18, 8,9,10,19,20,21

然后 0,11,1,12,2,13,3,14,4,15,5,16,6,17,7,18, 8,9,10,19,20,21

第二次:

0,1,2,3,4,5,6,7,11,12,13,14,15,16,17,18, 8,9,10,19,20,21

变为 0,1,2,3,4,5,6,7,11,12,13,14,15,16,17,18, 8,9,19,20, 10,21

然后 0,11,1,12,2,13,3,14,4,15,5,16,6,17,7,18, 8,19,9,20, 10,21

证明对任意n该方法的时间复杂度为O(N),有两种证明方法:

1、采用master theorem[2],可直接证明。

2、到n=2^k-1时,该算法的时间复杂度最大。因此,只需证明此时的时间复杂度为O(N)。

利用等比数列,可以证明此结论。

算法与证明描述结束。

[1] 编程之美。问题2.17。

[2] 算法导论。定理4.1

/**
* @author Administrator
*
*/
public class TestShuZushuanFa {

/**
*
*/
public TestShuZushuanFa() {
// TODO 自动生成构造函数存根
}

public static void test(int[] arr, int size) {
int temp = arr[size / 2];
for (int i = size / 2; i != 1;) {
arr[i] = arr[(i + (i % 2) * (size - 1)) / 2];
// 奇数加(数组长度-1)除以2 偶数直接除以2
i = (i + (i % 2) * (size - 1)) / 2;

}
arr[1] = temp;

for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+",");
}

}

/**
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根
int[] number = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
test(number, 20);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐