内容专栏:《LeetCode刷题专栏》
本文概括:189.轮转数组
本文作者:花 碟
发布时间:2023.4.12
目录
思想1 暴力求解
代码实现:
思想2 三次倒置
代码实现:
思想3 memcpy零时拷贝
代码实现:
189.轮转数组 点击跳转到LeetCode平台OJ页面
题目:
给定一个整数数组
nums
,将数组中的元素向右轮转k
个位置,其中k
是非负数。
示例1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
示例2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
从右边开始,每轮移动一次,移动k轮,但是这种解法最坏的情况是k等于numsSize - 1,每轮又要移动numsSize - 1次。时间复杂度为O(k*n),或者说是O(n^2)
画图分析:
void rotate(int* nums, int numsSize, int k){
if(k > numsSize)
{
k %= numsSize;
}
while(k)
{
int tmp = nums[numsSize - 1];
int i = 0;
for(i = numsSize - 2;i >= 0;i--)
{
nums[i + 1] =nums[i];
}
nums[0] = tmp;
k--;
}
}
我们以这种方法去写固然可行,但是放入leetcode之中,再去提交的时候,只通过了37/38个测试用例,leetcode检测过于严格,通过不了,那么这种方式去写就不太合适了,有没有更加好的解法思想呢?我们往下看。
第1步.我们从k处分隔数组,分为左右两边,各自进行倒置即可;
第2步.对整个数组进行倒置,这样子就会让最开始想要翻转的数组个数挪动到前面了。
注⚠️:也可以先进行第二步,再进行第1步,此方法无先后顺序,最终都能达到效果。
画图分析:
注⚠️: k 必须要保证小于numsSize,否则提交代码会出现以上图片中的执行错误,原因是数组出现越界,将执行结果,numsSize为1,k = 2,代入第一个reverse函数,结果为-1,故会出现数组越界,此外,k需要避免过大,进行多次无效的重复运算,以示例1为例,数组翻转8次就相当于数组翻转1次。
void reverse(int* nums,int left,int right)
{
while(left < right)
{
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left++;
right--;
}
}
void rotate(int* nums, int numsSize, int k){
if(k > numsSize)
{
k %= numsSize;//去掉if条件判断也行
}
reverse(nums,numsSize - k,numsSize - 1);//右边倒置
reverse(nums,0,numsSize - k - 1);//左边倒置
reverse(nums,0,numsSize - 1);//整体倒置
}
我们利用malloc申请一块为numsSize元素*int类型大小的内存空间,我们从k处分隔原数组,利用memcpy函数先将后面的k个元素拷贝到内存空间,再次将前numsSize - k个元素拷贝到k个元素的后面,最后将内存空间的numsSize*sizeof(int)个字节空间拷贝到原数组之中。
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,(numsSize - k) * sizeof(int));
memcpy(nums,tmp,sizeof(int) * numsSize);
//
free(tmp);
//tmp = NULL
}
这篇文章就到此为止了,如果对你有帮助,还请多多支持博主哦~~