《LeetCode之每日一题》:17. 旋转数组

旋转数组


题目链接: 旋转数组

有关题目

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
进阶:

尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
示例 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 <= nums.length <= 2 * 10^4
-2^31 <= nums[i] <= 2^31 - 1
0 <= k <= 10^5

题解

1、暴力法(超时)

void rotate(int* nums, int numsSize, int k){
    //暴力求解法--旋转k次
    while(k--)
    {
    int tmp = nums[numsSize - 1];
    for (int i = numsSize - 2; i >= 0; i--)
    {
        nums[i + 1] = nums[i];
    }
    nums[0] = tmp;
    }
}

2、以空间换时间–开辟额外空间
代码一:

void rotate(int* nums, int numsSize, int k){
	k %= numsSize;//我们只保证0~numsSize内的反转
   int* tmp = (int*)calloc(numsSize,sizeof(int));
    memcpy(tmp,nums + numsSize - k,sizeof(int) * k);
    memcpy(tmp + k,nums,sizeof(int) * (numsSize - k));
    memcpy(nums,tmp,numsSize * sizeof(int));
}

代码二:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> newArr(n);
        for (int i = 0; i < n; ++i){
            newArr[(i + k) % n] = nums[i];
            //从(i + k) % n 开始拷贝
        }
        nums.assign(newArr.begin(), newArr.end());
    }
};

时间复杂度:O(N).涉及到拷贝次数
空间复杂度:O(N)多开辟了numsSize大小的空间
在这里插入图片描述
3、环状替换
参考官方题解

int gcd(int a, int b){// 8 4   4 0
    return b ? gcd(b, a % b) : a;
}
void swap(int* a, int* b){
    int x = *a;
    *a = *b, *b = x;
}
void rotate(int* nums, int numsSize, int k){
    int n = numsSize;
    int cnt = gcd(n, k);    
    for (int i = 0; i < cnt; ++i){
        //
        int cur = i;
        int pre = nums[i];
        do{
            int next = (cur + k) % n;
            swap(&pre, &nums[next]);
            cur = next;
        }while(cur != i);
    }
}

4、三次反转

思路:
①先反转前numsSize - k 个元素
②再反转后k个元素
③最后整体反转
以下面的数组为例
1,2,3,4,5,6,7--k = 3
前numsSize - k 个元素反转--> 4 3 2 1 5 6 7
后k 个元素反转-->4 3 2 1 7 6 5
整体反转-->  5 6 7 1 2 3 4

C

void Reverse(int* begin,int* end)
{
    int* l = begin;
    int* r = end;
    while(l <= r)
    {
        int tmp = *l;
        *l = *r;
        *r = tmp;
        l++;
        r--;
    }
    return ;
}
void rotate(int* nums, int numsSize, int k){
    k %= numsSize;//你不叫这个就会出现一定程度的错误
    Reverse(nums,nums + numsSize - k - 1);
    Reverse(nums + numsSize - k,nums + numsSize - 1);
    Reverse(nums,nums+numsSize - 1);
    return ;
}

C++

class Solution {
public:
    void reverse(vector<int>& nums, int l, int r){
        while(l < r){
            int tmp = nums[l];
            nums[l] = nums[r];
            nums[r] = tmp;
            ++l, --r;
        }
    }
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k %= n;
        reverse(nums, 0, n - k - 1);
        reverse(nums, n - k, n - 1);
        reverse(nums, 0, n - 1);
    }
};

代码二:

class Solution {
public:
    void rotate(vector<int>& nums, int k) 
	{
        k=k%nums.size();
        reverse(nums.begin(),nums.end());
        reverse(nums.begin(),nums.begin()+k);
        reverse(nums.begin()+k,nums.end());
    }
};

时间复杂度:O(N)
空间复杂度:O(1)

在这里插入图片描述

1,2,3,4,5,6,7--k = 4为例
多种方式进行反转
下面的反转都是按照先前numsSize - k 个元素
再后k 个元素
最后整体反转
①上式中
②函数实现:Reverse(nums,int l,int r){
	while(l < r)
	{
	//创建临时变量
		int tmp = nums[l];
		nums[l++] = nums[r];
		nums[r--] = tmp;
	//加减运算
	nums[l] = nums[l] + nums[r];
	nums[r] = nums[l] - nums[r];
	nums[l] = nums[
	}
}
Reverse(nums,0,numsSize - k - 1)
Reverse(nums,numsSize - k,numsSize - 1)
Reverse(nums,0,numsSize - 1)

Reverse
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值