LeetCode 189 旋转数组

补数据结构的作业的时候,被老师要求写出时间复杂度为O(n),空间复杂度为O(1),的算法。断断续续想了一天,终于有了一个大概思路,写出来自己跑了几组数据,没发现什么问题。在LeetCode上找到了这道题提交了一下,用时战胜了89%的提交者(最优的那种算法真的是简单又高效,但是我实在是没有想出来,就不在这里剽窃了)。下面叙述一下我的想法。

首先明确,k>=n时,应有k%=n,因为移动一圈跟不动是没区别的。

大概的思路是从a元素出发,把它放到它在结果中应该到的位置(设为b)中去,并保存b位置原来的值。然后从b位置出发,重复该操作,又回到a位置(eg. a->b->c->e->a)之后,如果数组中的元素还没有移动完毕,应该移动到a+1,然后继续循环移动 。

那么问题是如何确定是否已经将数组中的元素全部移动完毕和是否已经绕了一圈呢?

经过思考,我们会发现经过多少个圈才能移动完成和每圈需要移动的元素数是可以根据n和k算出来的。

1. 确定每圈可以移动的元素数

当我们从a出发又回到a时,走过的长度是n和k的最小公倍数,而 最小公倍数=(n*k)/gcd(n,k),同时,每移动k步就意味着一个元素的移动,因此 每圈移动的元素数为 n/(gcd(n,k))

2.圈数

n/(n/(gcd(n,k)))=gcd(n,k)

代码如下

void rotate(vector<int>& nums, int k) {
        int n=nums.size();
        k%=n;
        if(k)
        {
            int gnk=gcd(n,k),temp,next,cur;
            for(int i=0;i<gnk;i++)
            {
                cur=i;
                temp=nums[i];
                for(int j=0;j<n/gnk;j++)
                {
                    next=(cur+k)%n;//循环移动
                    swap(temp,nums[next]);
                    cur=next;
                }
            }
        }
    }
    int gcd(int a,int b)//在这里用欧几里得算法计算最大公约数
    {
        int t;
        while(b)
        {
            t=a;
            a=b;
            b=t%a;
        }
        return a;
    }
    void swap(int& a,int& b)//三变量法元素交换
    {
        int t;
        t=a;
        a=b;
        b=t;
    }

强烈推荐去了leetcode上看看其他解法,比我这个强多了

猜你喜欢

转载自blog.csdn.net/Accsc/article/details/80528472