力扣OJ题——旋转数组

题目:189.旋转数组  

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数

63d298eb5fac4db88f61a4a5c820d102.png

思路一:

1.每次挪动旋转1位(用tmp将最后一位存起来,其余所有数据向后移,然后将tmp放在第一个位置)

2.右旋k位

知道了思路的步骤,我们也先不着急实现,先来分析一下它的时间复杂度~:

我们知道每次挪动旋转1位的时间复杂度是O(N)

接下来右旋k位,这里就要分最好情况和最坏情况了:

最好情况:k是N的倍数时,我们不需要挪动,时间复杂度是O(1)

最坏情况:k%N = N-1   则要执行N*(N-1)次 时间复杂度是O(N^2)

我们知道时间复杂度是取最坏情况的

综上,思路一的时间复杂度是O(N^2)

不过这个思路博主已经在力扣上跑过了,最终超出时间限制,所以对于这道题目,时间复杂度为

O(N^2) 是不行的,我们得用其他的,时间复杂度更低的思路实现~

接下来我们来看一下思路二:

1.前n-k个逆置

2.后k个逆置

3.整体逆置

同样,我们也来分析一下它的时间复杂度,看看它的性能是否值得我们去写

简单计算得出是2*N,所以它的时间复杂度是O(N)

接下来我们就来实现一下

这里我先单独写一个逆置函数,因为这个功能我们等会要用三次, 单独写一个才更加方便之后的复用~

void Reverse(int* nums, int start, int end) //写一个逆置的函数
{while (start <end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start ++;end --;}
}

接下来我们写一下rotate函数,其实写完上面这个函数后就非常简单了:

代码如下:

void rotate(int* nums, int numsSize, int k)
{k %= numsSize;//防止越界Reverse(nums, 0, numsSize-k-1);//前n-k个逆置Reverse(nums, numsSize-k, numsSize-1);//后k个逆置Reverse(nums, 0, numsSize - 1);//整体逆置
}

这个思路就可以通过啦~

543f41a5668b42e4a2dd9fbfee109142.png

好,这是这个题的第二个思路

但是这个思路二的难点在于它怎么想出来,如果我们第一次做这类题,恐怕 还是难以下手,那么有没有我们初见就能想出来并且能过通过测试的思路呢?

所以接下来再看一下思路三~

思路三:

1.创建一个新的数组tmp

2.将原数nums后面的k个拷贝到新数组tmp前面的位置

(原数组对应下标为n-k~n-1,新数组对应下标为0~k-1)

3.将原数组nums前面的n-k个拷贝到新数组tmp后面的位置

(原数组对应下标为0~n-k-1,新数组对应下标为k~n-1)

4.将拷贝完的tmp的数据放回原数组nums中

思路有了,我们也先看一下它的时间复杂度是否可行:

先拷后k个,再拷前n-k个用了n再整体拷回,

所以总共是2*n   即时间复杂度是O(N)

既然可行,

下面来写一下代码

这里的拷贝博主直接使用memcpy函数,关于memcpy的具体用法可以在Cplusplus中搜索

这里我就大概介绍一下:

e2bf1fc19c2d4ceebf6b4f9c66cadb3b.png

从函数的定义中,我们可以看出第一个参数是目标,第二个是原,第三个参数是字节数

代码如下:

void rotate(int* nums, int numsSize, int k)
{k %= numsSize;//防止越界int tmp[numsSize];int n = numsSize;;memcpy(tmp,nums+n-k,sizeof(int)*k);memcpy(tmp+k,nums,sizeof(int)*(n-k));memcpy(nums,tmp,sizeof(int)*n);
}

然后就过了

fb3f395067774eb1ba2b3c70a9567312.png

好啦,今天的旋转数组问题就结束啦,如果文中分析,题解代码有不足的地方欢迎大家在评论区讨论和指正

让我们在接下来的时间里一起学习,一起进步吧~

c0fe1378f4b1464abb37998a472b5961.jpg