【LeetCode】轮转数组

简介: 【LeetCode】轮转数组

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]

思想1 暴力求解

从右边开始,每轮移动一次,移动k轮,但是这种解法最坏的情况是k等于numsSize - 1,每轮又要移动numsSize - 1次。时间复杂度为O(k*n),或者说是O(n^2)

画图分析:

image.png

代码实现:

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--;
   }
}

image.png

我们以这种方法去写固然可行,但是放入leetcode之中,再去提交的时候,只通过了37/38个测试用例,leetcode检测过于严格,通过不了,那么这种方式去写就不太合适了,有没有更加好的解法思想呢?我们往下看。


思想2 三次倒置

第1步.我们从k处分隔数组,分为左右两边,各自进行倒置即可;


第2步.对整个数组进行倒置,这样子就会让最开始想要翻转的数组个数挪动到前面了。


注⚠️:也可以先进行第二步,再进行第1步,此方法无先后顺序,最终都能达到效果。


画图分析:  


image.png

image.png

image.png

注⚠️: k 必须要保证小于numsSize,否则提交代码会出现以上图片中的执行错误,原因是数组出现越界,将执行结果,numsSize为1,k = 2,代入第一个reverse函数,结果为-1,故会出现数组越界,此外,k需要避免过大,进行多次无效的重复运算,以示例1为例,数组翻转8次就相当于数组翻转1次。


image.png

image.png

代码实现:

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);//整体倒置
}

思想3 memcpy拷贝数组

我们利用malloc申请一块为numsSize元素*int类型大小的内存空间,我们从k处分隔原数组,利用memcpy函数先将后面的k个元素拷贝到内存空间,再次将前numsSize - k个元素拷贝到k个元素的后面,最后将内存空间的numsSize*sizeof(int)个字节空间拷贝到原数组之中。


对memcpy函数不熟悉的小伙伴,这里放出库函数的使用规则,更详细内容,可以在cplusplus 官网进行搜索查看哦


image.png

image.png

代码实现:

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
}
目录
相关文章
|
1月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
1月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
LeetCode------找到所有数组中消失的数字(6)【数组】
这篇文章介绍了LeetCode上的"找到所有数组中消失的数字"问题,提供了一种解法,通过两次遍历来找出所有未在数组中出现的数字:第一次遍历将数组中的每个数字对应位置的值增加数组长度,第二次遍历找出所有未被增加的数字,即缺失的数字。
|
1月前
|
前端开发
LeetCode------移动零(5)【数组】
这篇文章介绍了LeetCode上的"移动零"问题,提出了一种使用双指针的原地操作解法,该方法首先将非零元素移动到数组前端并保持相对顺序,然后填充后续位置为零,以达到题目要求。
|
1月前
|
算法
LeetCode第81题搜索旋转排序数组 II
文章讲解了LeetCode第81题"搜索旋转排序数组 II"的解法,通过二分查找算法并加入去重逻辑来解决在旋转且含有重复元素的数组中搜索特定值的问题。
LeetCode第81题搜索旋转排序数组 II
|
1月前
|
算法 索引
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
这篇文章介绍了LeetCode第34题"在排序数组中查找元素的第一个和最后一个位置"的解题方法,通过使用双指针法从数组两端向中间同时查找目标值,有效地找到了目标值的首次和最后一次出现的索引位置。
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
|
1月前
|
算法
LeetCode第33题搜索旋转排序数组
这篇文章介绍了LeetCode第33题"搜索旋转排序数组"的解题方法,通过使用二分查找法并根据数组的有序性质调整搜索范围,实现了时间复杂度为O(log n)的高效搜索算法。
LeetCode第33题搜索旋转排序数组
|
1月前
|
存储 索引
LeetCode------两数之和(3)【数组】
这篇文章介绍了LeetCode上的"两数之和"问题,提供了两种解法:一种是暴力求解法,通过双层循环遍历数组元素对查找两数之和为目标值的索引,时间复杂度为O(n^2);另一种是使用HashMap优化,通过存储元素值和索引,时间复杂度降低到O(n)。
LeetCode------两数之和(3)【数组】
|
1月前
|
算法 Java 索引
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
LeetCode初级算法题:寻找数组的中心索引+x的平方根+三个数的最大乘积+Leetcode 149:直线上最多的点数 Java详解
28 0
|
1月前
|
存储 算法 Java
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
18 0