• 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;
            }
        }
    };
    



    参考


  • 相关阅读:
    【bozj2287】【[POJ Challenge]消失之物】维护多值递推
    书籍
    图书管理系统-单表的增删改查
    Django之ORM
    app的创建和注册
    登陆示例
    django 静态文件配置
    安装django及配置
    Bootstrap
    导图
  • 原文地址:https://www.cnblogs.com/Bw98blogs/p/12664207.html
Copyright © 2020-2023  润新知