Leetcode--轮转数组【189】解题思路

Leetcode–轮转数组【189】


#题目

题目描述:给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。


提示:以下是本篇文章正文内容,下面案例可供参考

一、模拟方法

模拟方法,通过计算每一个元素的新位置,进行赋值(多开一组空间),公式如下:
移动公式
根据求余运算公式的分配律:
在这里插入图片描述
更新公式:
在这里插入图片描述
其中old_ID必然小于等于N(数组长度),K则未必,当K是N的整倍数时,则无需计算移动,通过复制数组,代码如下:

class Solution {
public:

    void rotate(vector<int>& nums, int k) {
        int lens = nums.size();
        if(k % lens !=0 ){
            int kk= k % lens;
            vector<int> tmp(lens,0);
            //copy nums
            for (int i =0; i<lens; i++){
                tmp[i] = nums[i];
            } 
            //
            for(int i =0; i<lens; i++){
                int new_i = 0;
                new_i = (i + kk) % lens;
                nums[new_i] =tmp[i];
            }
        }
       
    }
};

时间复杂度O(N),空间O(N),因为用到了复制。

二、遍历

针对第一种的空间复杂度, 由于移动是连续的,a1移动到a2(a1+kk)mod n, a2必定会移动到a3(a2+kk) mod n, 因此可以仅保留待移动变量, 使得空间复杂度降低为O(1)。
但这里有一个坑, 就是当KK=1时, 这么移动可以覆盖每一个数组元素, 当KK为其他数值时,可能会漏掉某些元素。
当从start起点开始, 再次回到start时,跳了b步,最少进行了 a圈(不一定是1圈),走过了an=bk个长度, an = bk, an也是 n, k的最小公倍数,b=lcm(n,k)/k。 每挑一步,就是一次访问, 所以单次遍历(回到起点)会访问b个元素, 还需要n/b次,才能访问完所有元素。
做这种回到起点的遍历,需要x次, x = nk/lcm(n,k) = gcd(n,k)-----最小公倍数lcm , 最大公约数gcd

class Solution {
public:

    void rotate(vector<int>& nums, int k) {
        int lens = nums.size();
        if(k % lens !=0 ){
            // 求余
            int kk = k %lens;

            int move_count = gcd(kk, lens);
            for(int start  =0; start < move_count; ++start){
                int current_id = start;
                int prev_number = nums[start];
                // do-while 先做后判断,while 先判断再 做
                do{
                    int next_id = (current_id + kk )% lens;
                    swap(nums[next_id], prev_number);
                    current_id = next_id;
                }while(start != current_id );

            }
        }
       
    }
};

三、翻转数组

.翻转数组的原理,如下图所示:
在这里插入图片描述
相应的代码如下:

class Solution {
public:
    void reverseArrary(vector<int>& arr, int begin, int end){
        int tmp = 0;
        int left = begin, right = end;
        while(left < right){
            tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
            left++;
            right--;
        }

    }
    //重点是K>length时的处理,要求余,整除不移动。
    void rotate(vector<int>& nums, int k) {
        int lens = nums.size();
        if(k % lens !=0 ){
            int kk= k % lens;
            reverseArrary(nums, 0, lens-1);
            reverseArrary(nums, 0, kk-1);
            reverseArrary(nums, kk, lens-1); 
        }
       // return nums
    }
};

总结

整体上有模拟的思路->空间优化->寻找特殊规律。 个人感觉套用代码模板、公式,这种解题思路会更清晰,复用性更强。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值