题目
给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
思路一
假设数组为nums = {1, 2, 3, 4, 5, 6, 7}
1、先把最后一个元素拿出来
int tmp = *(nums + numsSize - 1);
2、把倒数第二个元素往后移一个位置
int end = numsSize - 2;
nums[end + 1] = nums[end];
把6挪过去后,再让end指向5,同样往后挪
3、重复上述过程,直到把7之前的所有元素都移位完成,再把7放到首位
int tmp = *(nums + numsSize - 1);
for (int end = numsSize - 2; end >= 0; end--)
{
nums[end + 1] = nums[end];
}
nums[0] = tmp;
这样就将数组中的元素向右轮转 1 个位置
如果要轮转 k 次,加上循环即可
void rotate(int* nums, int numsSize, int k)
{
while (k--)
{
int tmp = *(nums + numsSize - 1);
for (int end = numsSize - 2; end >= 0; end--)
{
nums[end + 1] = nums[end];
}
nums[0] = tmp;
}
}
运行一下,发现跑不过,因为测试用例中,给了一个大数组,程序运行超出时间限制,也就是说这种方法在某些情况下效率较低
当前算法的时间复杂度:O(N*K)
思路二
1、新建一个数组 nums1
2、将要轮转的部分整段移动过去
3、再把 nums1 的内容交还给 nums
这种算法的时间复杂度是 O(N),空间复杂度也是 O(N)
效率还是不够高,并且当给定的数组很大时,空间有可能不够用
思路三
流程
nums:1, 2, 3, 4, 5, 6, 7
k = 3
1、后 k 个逆置:1, 2, 3, 4, 7, 6, 5
2、前 n - k 个逆置:4, 3, 2, 1, 7, 6, 5
3、再整体逆置:5, 6, 7, 1, 2, 3, 4
逆置的实现
1、首尾交换
2、指针内移
3、再次交换,重复上面的过程,直至 left >= right
重点
在进行逆置时,一定要控制好元素的下标,即 Reverse (逆置函数)的实参
[1, 2, 3, 4, 5, 6, 7]
后k个逆置
5的下标为N-K,7的下标为N-1
[1, 2, 3, 4, 7, 6, 5]
前n-k个逆置
1的下标为0,4的下标为N-K-1
[4, 3, 2, 1, 7, 6, 5]
再整体逆置
4的下标为0,5的下标为N-1
完成
[5, 6, 7, 1, 2, 3, 4]
代码实现
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;//每轮转numsSize次,相当于返回原状。如果不进行取余,N-K可能小于零,会导致数组越界
}
Reverse(nums, numsSize - k, numsSize - 1);
Reverse(nums, 0, numsSize - 1 - k);
Reverse(nums, 0, numsSize - 1);
}