一个任意长度的数组,选取一个分割点,将数组分成前后两部分,交换前后两部分的数据。
要求:算法复杂度O(n)
这是标准答案:
void swap2parts(int *a,int len,int split){
int *temp;
int lenB = len-split;
if(lenB<split){
temp = (int *)malloc(split*sizeof(int));
memcpy(temp,a,split*sizeof(int));
memcpy(a,a+split,lenB*sizeof(int));
memcpy(a+lenB,temp,split*sizeof(int));
}else{
temp = (int *)malloc(lenB*sizeof(int));
memcpy(temp,a+split,lenB*sizeof(int));
memcpy(a+len-split,a,split*sizeof(int));
memcpy(a,temp,lenB*sizeof(int));
}
free(temp);
}
适合面试新手菜鸟
该题进阶的版本是:
交换两个数组部分,但是将空间复杂度限定在O(1),算法复杂度O(n)
可通过缩小问题范围的方式来求解
比如交换8和3两个长度的数组
0 1 2 3 4 5 6 7 | 8 9 10
可以将8按3份3份的分开
0 1 (2 3 4) (5 6 7)|( 8 9 10)
每次轮转一个位置
—>
0 1 (8 3 4) (2 6 7)|( 5 9 10)
最后得到
0 1 (8 9 10) (2 3 4)|(5 6 7)
于是问题转化为
0 1|8 9 10
如此N次后得解
注意不要用递归来实现,用递归等于隐性的申请了O(n)的空间
再进一步,如果把设置数组值的次数限制在N步以内(N<=数组长度),这道题怎么做?
直觉上,我们相信,如果从第一个元素开始,将该元素直接放入到该元素的最终目的地,而目的地的值又去顶替目的地的目的地的值……如此下去,必然会遍历所有的元素,最后回到第一个元素,并完成交换,比如:
0 1 2 | 3 4
可按如下顺序遍历
0->3->1->4->2->0
注意步进长度只有3和-2两个值,正好是分割后数组的长度。
但也会有不能遍历完整的情况,比如12和8:
0->8->16->4->12->0
注意到这种情况中,两个数组长度存在大于1的最大公约数,因此先求出最大公约数m,再将该遍历走m遍即可。
上述两种解法源代码不给出,有兴趣的童鞋可以试试实现。如果你发现更少步骤更少空间能完成这个交换的方法欢迎提出。