面试题:如何交换数组的两个部分

想了个很基础很实用的 机试题,面试的时候自己会出。
一个任意长度的数组,选取一个分割点,将数组分成前后两部分,交换前后两部分的数据。
要求:算法复杂度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遍即可。

上述两种解法源代码不给出,有兴趣的童鞋可以试试实现。如果你发现更少步骤更少空间能完成这个交换的方法欢迎提出。

你可能感兴趣的:(c,算法,面试题)