LeetCode #189 Rotate Array 数组 双变量 双指针

Description


Given an array, rotate the array to the right by k steps, where k is non-negative.

Example 1:

Input: [1,2,3,4,5,6,7] and k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]

Example 2:

Input: [-1,-100,3,99] and k = 2
Output: [3,99,-1,-100]
Explanation: 
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]

Note:

  • Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
  • Could you do it in-place with O(1) extra space?



思路


解法一

拷贝一份源数组,以便在覆盖 nums 里的元素之后能够检索到该位置的旧值是什么,从而在下次更新 nums 时使用该旧值。

算法只需要 nums.size() 次更新操作,所以时间复杂度为 O(n);拷贝了一份数组,空间复杂度 O(n)

耗时16ms, ranking 80%

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if (nums.empty()) return;

        k = k % nums.size();
        if (!k) return;

        vector<int> backup = nums;
        for (int i = 0; i < nums.size(); ++i) {
            int next_idx = abs(i + k) % (nums.size());
            nums[next_idx] = backup[i];
        }
    }
};



解法二

如果只观察间隔为 k 的元素的更新操作,比如 [1 2 3 4 5], k = 2 的话,只看 [1 3 5] 这三个位置的更新操作,那么在每次更新操作中,真正被用到的数据只有上一次被覆盖元素的值与索引,比如更新 3 时,我们用到了值 1 和索引 0。因此可以利用双变量、双索引保存旧值与其位置,从而对解法一进行优化。

额外需要注意的是,由于解法二是 pick 出了间隔为 k 的元素,那么就可能会漏掉另一部分的元素,比如上一段话中的 [2 4] 就被忽略了,因为 k = 2 时,指针永远在 [1 3 5] 这三个数据之间循环。因此,需要再加入一个保存起始位置的索引start_idx,当指针等于start_idx时, 说明当前更新操作陷入局部数据而死循环了,需要将start_idx与当前指针都自增,从而脱离死循环。

算法最终会对数组的每个位置都执行一次更新操作,所以总共执行 nums.size() 次更新操作,时间复杂度为 O(n);用了五个临时变量保存算法必要的信息,空间复杂度 O(1)

耗时16ms, ranking 80%

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if (nums.empty()) return;

        k = k % nums.size();
        if (!k) return;

        int idx = 0;
        int start_idx = idx;  // mark starting point
        int prev = INT_MAX;
        int cur = nums[idx];
        int update_cnt = nums.size();  // only update size() times
        while (update_cnt > 0) {
            int next_idx = abs(idx + k) % (nums.size());
            prev = cur;
            cur = nums[next_idx];
            nums[next_idx] = prev;
            idx = next_idx;

            // avoid endless loop caused by even k
            if (idx == start_idx) {
                ++start_idx;
                idx = start_idx;
                cur = nums[idx];
            }

            --update_cnt;
        }
    }
};



参考


原文地址:https://www.cnblogs.com/Bw98blogs/p/12664207.html