LeetCode------颠倒数组

这篇博客探讨了如何在LeetCode中解决‘颠倒数组’的问题,提出了三种空间复杂度为O(1)的原地算法:记录后移法、跳跃赋值法和翻转法。通过示例解释了每种方法的工作原理,并指出只需考虑数组长度与移动次数k的公因子是否大于1的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://leetcode-cn.com/problems/rotate-array/

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

示例 1:

输入: [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:

输入: [-1,-100,3,99]k = 2
输出: [3,99,-1,-100]
解释: 
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]

说明:

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
  • 要求使用空间复杂度为 O(1) 的原地算法。

 

解法1:记录最后一个元素,将除最后一个元素外的所有元素后移一格,首元素赋值为尾元素,重复k次

void rotate(int* nums, int numsSize, int k) {
    int p = nums[numsSize-1];
    while(k--){
        p = nums[numsSize-1];
        for(int i = numsSize-1;i>0;i--){
            nums[i] = nums[i-1];
        }
        nums[0] = p;
    }
}//空间复杂度O(1)时间复杂度O(k*n)

解法2:跳跃赋值法

请先看以下几个例子:

[1,2,3,4,5,6,7]k = 3

若从首位置开始,间隔k跳跃赋值,那么顺序是1->4->7->3->6->2->5->1,刚好通过n次遍历完数组,那么只需将前一个值赋给后一个,就可以完成数组变换,而数组长度与k公因子为1.

 [1,2,3,4,5,6] 和k=4 

1->5->3->1

2->6->4->2

通过两次循环可以将所有元素赋值更换,同样经过n次操作,而数组长度numsSize与k的公因子为2.

综上所述,我们只需考虑数组长度与k的公因子是否大于1这两种情况(实际上两种情况可以合并成一种情况)。

int gcd(int a,int b);
void rotate(int* nums, int numsSize, int k) {
    int next = 0,pre=0,gcd1=0;
    if(k==0) return ;
    if(numsSize==1) return ;
    gcd1 = gcd(numsSize,k);
    for(int i = 0;i < gcd1;i++)  //控制循环次数
    {   
        pre = nums[i];
        next = nums[i];
        for(int j = i,count=0;count<numsSize/gcd1;count++){//每次循环将前值赋给当前值
            next = nums[j];              //保存当前值
            nums[j] = pre;               //赋值
            pre = next; 
             j = (j+k)%numsSize;    //通过取模操作,控制下标不越界
        }
        nums[i] = next;             //将未处理的首元素赋值
    }
}
int gcd(int a,int b){                 //辗转相除法求最大公因子
    int rem=0;
    while(1){
        rem = a%b;
        if(rem==0) return b;
        else{
            a = b;
            b = rem;
        }
    }
}//求最大公因子

方法3:翻转法

[1,2,3,4,5,6]和k = 2 

将[1,2,3,4]翻转为[4,3,2,1],将[5,6]翻转为[6,5]

这样数组变成[4,3,2,1,6,5]

再总体翻转

得到[5,6,1,2,3,4]

void reserve(int* nums,int left,int right);
void rotate(int* nums, int numsSize, int k) {
    if(k==0 || numsSize==1 || (k%numsSize==0 && k!=1)) return;   //排除特殊情况
    k %= numsSize;                          //缩小范围
    reserve(nums,0,numsSize-1);             //函数位置不要任意改变
    reserve(nums,0,k-1);
    reserve(nums,k,numsSize-1);
}
void reserve(int* nums,int left,int right){
    if(left>=right) return;
    int temp;
    while(left<right){
        temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
        left++,right--;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值