15 轮转数组

轮转数组

    • 题解1 环状替换(学习思想)(空间O(1))
    • 题解2 翻转数组(有意思好理解)(空间O(1))
    • 题解3 空间O(N)秒答

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 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 <= n u m s . l e n g t h nums.length nums.length <= 1 0 5 10^{5} 105
  • − 2 31 -2^{31} 231 <= nums[i] <= 2 31 2^{31} 231 -1
  • 0 <= k <= 1 0 5 10^{5} 105

进阶:

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

题解1 环状替换(学习思想)(空间O(1))

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        const int s = nums.size();// 先处理k(减少后面的不必要循环)
        k = k % s;
        // cylimit 就是为了保证能把元素全部遍历, 设最小遍历次数为N
        // N = as = bk (等式基于遍历经过的长度)-> N 应该是s, k的最小公倍数lcm(s, k)
        // lcm(s, k)/k = b 即遍历N次遍历过的元素总数目
        // cylimit = s / (1/k * lcm(s, k)) = sk / lcm(s,k) = gcd(s, k) 即s, k最大公倍数  
        int cylimit = gcd(k, s);
        for(int c = 0; c < cylimit; c++){
            // O(1): 把每个能计算到的位置对应的原来的值放在[c]的位置
            int cur = c;
           do{
               // 新下标
                int newI = (cur+k) % s;
                // 每次都把改变的值放在[c]上
                swap(nums[newI], nums[c]);
                // 循环找下一个
                cur = newI;
            }while(cur != c); // %的关键:停止条件是回到起始位置
        }

    }
};

15 轮转数组_第1张图片

题解2 翻转数组(有意思好理解)(空间O(1))

15 轮转数组_第2张图片

class Solution {
public:
    void reverse(vector<int>& nums, int start, int end){
        while(start < end){
            swap(nums[start], nums[end]);
            start ++;
            end --;
        }
    }
    void rotate(vector<int>& nums, int k) {
        const int s = nums.size();
        // 先处理k(减少后面的不必要循环)
        k = k % s;
        reverse(nums, 0, s-1);
        reverse(nums, 0, k-1);
        reverse(nums, k, s-1);
    }
};

15 轮转数组_第3张图片

题解3 空间O(N)秒答

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        const int s = nums.size();
        // 先处理k(减少后面的不必要循环)
        k = k % s;
        vector<int> newN(s, 0);
        for(int i = 0; i < s; i++){
            newN[(i+k)%s] = nums[i];
        }
        nums.assign(newN.begin(), newN.end());
    }
};

15 轮转数组_第4张图片

你可能感兴趣的:(HOT100,Math思想,leetcode,算法,数据结构)