189.轮转数组

解法一:

1 -解题思路

假设从下标0开始遍历,一直到遍历完成回到下标0完成轮转。

回到下标0时,可能中间有些元素并未遍历,此时从下标1开始依次遍历,一直到遍历完成回到下标1,如此循环往复,直到所有元素都遍历过了

假设一次遍历了b个元素,遍历了a圈,那么就有an=bk;an是n,k的公倍数,因为要使遍历圈数尽可能小,因此a为n,k最小公倍数(lcm(n,k)),b=an/k=lcm(n,k)/k;

那么一共要遍历n/b次,即

gcd(n,k)为最大公约数


例如:假定数组a[9]={8,5,9,6,2,1,1,4,5},n=9,k=3,最大公约数为start=3,因此要遍历3次

2 -解题方法

①欧几里得算法,辗转相除法求最大公约数

795/45=17......30

45/30=1......15

30/15=2......0

得出最大公约数是15

3 -Code
int gcd(int a,int b)//求numsSize和k的最大公约数
{
    return b?gcd(b,a%b):a;//①b为0时,返回:后面的值②b为1时,返回:前面的值
}                          //欧几里得算法,辗转相除求最大公约数
void swap(int *a,int *b)    
{
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
}
void rotate(int* nums, int numsSize, int k){
    k=k%numsSize;  //k求余,排除移动次数大于元素个数;
    int count=gcd(numsSize,k);  //求numsSize和k的最大公约数
    for(int start=0;start<count;start++)//循环count次
    {
        int current=start;      //本次循环开始要移动的元素下标
        int pre=nums[start];    //保留本次循环开始要移动的元素
        do{
         
        int next=(current+k)%numsSize;//目标位置
        swap(&pre,&nums[next]);        //目标位置与本次要移动元素交换数据
        current=next;                   //移动元素移动
        }while(start!=current);
    }
}

4 -算法分析

时间复杂度O(n^2)

空间复杂度O(1)

5 -总结

①辗转相除法求最大公约数

②两个数交换的代码多次使用可以单独写一个函数,这样代码简洁易读

③return b?gcd(b,a%b):a;b为0时,返回:后面的值;b为1时,返回:前面的值

解法二:

1 -解题思路

数组轮转过程可以分为三步

①数组下标0~numsSize-1翻转

②数组下标0~k-1翻转

③数组下标k~numsSize-1翻转

例如:假定数组a[9]={8,5,9,6,2,1,1,4,5},n=9,k=3
2 -解题方法

依次翻转元素即可,这里要注意翻转时使用while循环,并且用首尾指针记录元素下标,较简洁

while(start<end)

{

change(&nums[start],&nums[end]);

start+=1;

end-=1;

}

注意:而不是用for循环控制,这样下标很难表示,利用while只要写一个通用的函数就可以了

for(i=0;(i<numsSize/2)%numsSize;i++)

{

change(&nums[i],&nums[numsSize-1-i]);

}

3 -Code
void change(int *a,int *b)
{
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
}
void reverse(int *nums,int start,int end)
{
    while(start<end)        //轮转数组
    {
        change(&nums[start],&nums[end]);
        start+=1;
        end-=1;
    }
}
void rotate(int* nums, int numsSize, int k){
    k%=numsSize;       //k求余,排除移动次数大于元素个数; 
    reverse(nums,0,numsSize-1);
    reverse(nums,0,k-1);
    reverse(nums,k,numsSize-1);
}
4 -算法分析

时间复杂度:O(n),每个元素被翻转两次O(2n)

空间复杂度:O(1),没有使用额外的空间

5 -总结

在考虑数组翻转时,首选while循环,并且对于重复的代码,可以封装成一个函数。

k对numsSize求余。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值