• 旋转数组 [ LeetCode ]


    原题地址:https://leetcode-cn.com/problems/rotate-array/description/

    给定一个数组,将数组中的元素向右移动 个位置,其中 是非负数。

    示例 1:

    输入: [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:

    输入: [-1,-100,3,99] 和 k = 2
    输出: [3,99,-1,-100]
    解释: 
    向右旋转 1 步: [99,-1,-100,3]
    向右旋转 2 步: [3,99,-1,-100]

    说明:

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

    以上是原题


    这道算法题目本身并不难,但要求使用三种不同方法解决问题,这就考验小伙伴们脑洞能开多大了。。。

    解法一:  

      首先用最普通的解法,根据题目描述,我们不难得出,将一个元素右移k个位置,原处于index位置的元素会出现在index + k 的位置上,如果index + k 超出数组长度,那么从0开始接着移动,新的下标等价于 (index + k) % length.

      直接上代码:

        //旋转数组
        public void rotate(int[] nums, int k) {
            int[] temp = Arrays.copyOf(nums, nums.length);
            for (int index = 0; index < temp.length; index++) {
                nums[(index + k) % temp.length] = temp[index];
            }
        }

      这种解法简单粗暴,效率也不错,但其实题目中要求尽量使用空间复杂度为O(1)的原地算法,上述解法使用了一个与输入数组同样大小的空间。

    解法二:

      移动第一个元素到k位置,将原本处在k位置的元素向右移动k位置,如果遇到了超出数组长度且指针指向数组第0个位置时,指针后移一位。

      

     1     public void rotate(int[] nums, int k) {
     2         if (nums.length == 0 || (k %= nums.length) == 0) {
     3             return;
     4         }
     5         int length = nums.length;
     6         int start = 0, index = 0, cnt = 0, temp = 0;
     7         int cur = nums[index];
     8         while (cnt++ < length) {
     9             index = (index + k) % length;
    10             temp = nums[index];
    11             nums[index] = cur;
    12             if (index == start) { //是否循环到已处理过的元素
    13                 ++start;
    14                 cur = nums[++index];
    15             } else {
    16                 cur = temp;
    17             }
    18         }
    19     }

      执行该方法时,数组状态变化如下:

      测试数据: [2, 7, 11, 15, 12, 16]   向右移动2位

      2   7   2  15  12  16    
      2   7   2  15  11  16    
      12  7   2  15  11  16    
      12  7   2  7   11  16
      12  7   2  7   11  15
      12  16  2  7   11  15

    解法三:

      这种方法比较特别,将原有数组用 length - k 分割为两段,分别对这两段中的数字进行首尾换位,然后再对整个数组进行首尾换位。

     1     public void rotate(int[] nums, int k) {
     2         k = k % nums.length;
     3         reverse(nums, 0, nums.length - 1 - k);
     4         reverse(nums, nums.length - k, nums.length - 1);
     5         reverse(nums, 0, nums.length - 1);
     6     }
     7 
     8     private void reverse(int[] nums, int start, int end) {
     9         while (start < end) {
    10             int tmp = nums[start];
    11             nums[start++] = nums[end];
    12             nums[end--] = tmp;
    13         }
    14     }

      同样给出数据状态:

      测试数据: [2, 7, 11, 15, 12, 16]   向右移动2位

      15  11  7   2  12  16    //第一次reverse
      15  11  7   2  16  12    //第二次reverse
      12  16  2   7  11  15    //第三次reverse

      坦白说,这个方法我没想明白什么原理,但的确很神奇,如果有朋友明白里的原理,还请不吝赐教啊。。。。。

  • 相关阅读:
    RDS MySQL 空间问题的原因和解决
    debian8最小化安装,字符界面的中文配置
    ekho安装及测试(中文文字转语音)
    sqlite 常用命令
    记录一次并没有什么用的对比测试
    debian 8 解压安装mysql(版本5.7.19)
    收藏的书录,值得花时间去读的书
    shell脚本监控Linux系统的登录情况
    gcc cc1: all warnings being treated as errors
    FreeSWITCH取消Digest校验流程
  • 原文地址:https://www.cnblogs.com/zfLee/p/9328633.html
Copyright © 2020-2023  润新知