【C语言】LeetCode 189. 轮转数组 的n种解法

本文涉及的库函数或者数据结构与算法不熟悉的地方,可以在文章末找到相关知识详解链接。

文章目录

  • 题目描述
  • 解法一 循环移位
  • 解法二 数组映射
  • 解法三 巧用反转

题目描述

OJ链接:LeetCode 189. 轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
【C语言】LeetCode 189. 轮转数组 的n种解法_第1张图片

解法一 循环移位

直接向右轮转k位,我们很难办到,但是我们可以分治他,一轮只移动每个元素1位,移动k轮,这样确保每个数据不会丢失。
注意:如果k超过数组的大小,就会轮转回原来数组,再轮转,不如使k对numsSize取余,只进行结果意义上的有效轮转。
时间复杂度:O(N) 准确时间复杂度 (K%numsSize)*N 可能会超出时间限制
空间复杂度:O(1)

void rotate(int* nums, int numsSize, int k)
{
    assert(nums);

    //只进行有效轮转
    k%=numsSize;
    
    //轮转k%numsSize趟
    for(int i=0;i<k;i++)
    {
        //对每趟数组元素进行移位
        int tmp=nums[numsSize-1];
        for(int j =numsSize-1;j>0;j--)
        {
            nums[j]=nums[j-1];
        }
        nums[0]=tmp;
    }

}//timeO(N) spaceO(1)

解法二 数组映射

假设我们有数组 [1,2,3,4,5,6],我们想要向右轮转2位,轮转结果应为 [5,6,1,2,3,4],如果直接向下标+2的位置进行轮转,数组最右侧数据会发生越界,我们可以对下标取余numsSize大小,即可消除越界。
你可以假设原数组有无限大,尽管向右移位多少距离都行,只是最后因为是有限大,利用取余将其限制在数组相应位置内。
时间复杂度:O(N) 准确时间复杂度 2*N
空间复杂度:O(N)

void rotate(int* nums, int numsSize, int k)
{
    assert(nums);

    //开辟临时数组,用于储存轮转好的数组
    int *tmp=(int*)malloc(numsSize*sizeof(int));
    if(tmp ==NULL)
    {
        printf("malloc fail\n");
        exit(-1);
    }

    for(int i=0;i<numsSize;i++)
    {
        //注意此思想轮转后,数的位置如何改变,可以举例解决,巧用取余
        tmp[(i+k)%numsSize]=nums[i];
    }

    //拷贝回原数组
    for(int i=0;i<numsSize;i++)
    {
        nums[i]=tmp[i];
    }

    //及时释放堆内存
    free(tmp);
    tmp=NULL;
}//timeO(n) spaceO(n)

解法三 巧用反转

反转数组是一个常见的操作,用在这题上十分巧妙,你可以在看后用笔画一画,试一试。
假设我们有数组 [1,2,3,4,5,6],我们想要向右轮转2位,轮转结果应为 [5,6,1,2,3,4]。

  1. 首先要使 k 对 numsSize 取余,才能确保后续操作正确且简洁。
  2. 我们先反转数组最右边 k 个数,得 [1,2,3,4,6,5]。
  3. 再反转数组最左边 numsSize-k个数,得[4,3,2,1,6,5]。
  4. 再对数组整体进行反转,得结果[5,6,1,2,3,4]

时间复杂度:O(N) 准确时间复杂度 2*N
空间复杂度:O(1)

//要被反转的数组首地址,区间[left,right]反转
void reverse(int *nums,int left,int right)
{
    assert(nums);

    while(left<right)
    {
        //需要使用交换两数功能,你可以也把这个常用功能封装成函数,这里就不封装了
        int tmp =nums[left];
        nums[left]=nums[right];
        nums[right]=tmp;

        //区间左右两头数交换后,向中间靠拢
        left++;
        right--;
    }
}

void rotate(int* nums, int numsSize, int k){
    assert(nums);

    //k超过numsSize大小的部分没意义
    k%=numsSize;

    //我们自己写一个反转数组的函数,注意传递的区间参数
    reverse(nums,numsSize-k,numsSize-1);
    reverse(nums,0,numsSize-k-1);
    reverse(nums,0,numsSize-1);

}

【C语言】交换两个变量的值 的n种方法


码字不容易,欢迎关注,点赞,收藏,评论,转发。

你可能感兴趣的:(LeetCode篇,leetcode,c语言,算法,数据结构,c++)