轮转数组:将数组中的元素向右轮转 k 个位置(c语言实现LeeCode.189:中等)

71 阅读2分钟

midjourney prompt:One afternoon, the warm sun shines through the shade of a young girl with white skin. The girl blushed slightly and looked at me with a smile. Detailed anime style with coordinated proportions.


在这篇博客文章中

我们将讨论三种在C语言中将固定长度序列的数组,元素向右移动'k'位的方法。

即元素向右轮转' k' 个位置。 如果元素挪动到了数组末尾,仍需要挪动,则从数组开头继续挪动)

我们这里使用动图来理解这个过程。

接下来所有的用例说明:将 后两个 数移动到整排数据的前面。即将数列右轮转‘2’位

(似乎也有“右旋”一说)

方法一:翻转法

翻转法的时间复杂度为O(N),空间复杂度为O(1)。我们可以通过以下三个步骤实现:

1.翻转前半部分。

2.翻转后半部分。

3.翻转整体。


步骤1和2:

动图封面

步骤3:

动图封面

代码部分:

void reverse(int* nums, int begin, int end) {
    while (begin < end) {
        int tmp = nums[begin];
        nums[begin] = nums[end];
        nums[end] = tmp;
        ++begin;
        --end;
    }
}
 
void rotate(int* nums, int numsSize, int k) {
    if (k > numsSize) {
        k %= numsSize;
    }
    reverse(nums, 0, numsSize - k - 1);
    reverse(nums, numsSize - k, numsSize - 1);
    reverse(nums, 0, numsSize - 1);
}

方法二:空间换时间法

空间换时间法的时间复杂度为O(N),空间复杂度为O(N)。我们可以通过将前后半段拷贝到一个新的数组中实现。

动图封面

读懂代码,你可能需要的知识:

memcpy(需要数据的地址,源头地址,字节数)

指针的加减的具体含义

#粗略认识:待整理完相关资料将为大家设置超链接详解

方法二 代码详解:

void rotate(int* nums, int numsSize, int k) {
    if (k > numsSize) {
        k %= numsSize;
    }
    int* tmp = (int*) malloc(sizeof(int) * numsSize);
    memcpy(tmp, nums + numsSize - k, sizeof(int) * k);
    memcpy(tmp + k, nums, sizeof(int) * (numsSize - k));
    memcpy(nums, tmp, sizeof(int) * numsSize);
    free(tmp);
}

方法三:依次交换法——直觉算法(无法通过leecode测试!)

时间复杂度为 O(K*numSize) ≈ O(N^2)。应该尽量避免使用

动图封面

具体代码实现:

void rotate(int* nums, int numsSize, int k) {
    if (k > numsSize) {
        k %= numsSize;
    }
    for (int i = 0; i < k; i++) {
        int last = nums[numsSize - 1];
        for (int j = numsSize - 1; j > 0; j--) {
            nums[j] = nums[j - 1];//相当于把‘K’之前的数,都往前挪动一位
        }
        nums[0] = last;
    }
}