Loading

旋转数组

1.问题描述

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

示例 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) 的 原地 算法。

2.求解

暴力法

  • 每次向后旋转1位,旋转k次
    

	public void rotate(int[] nums, int k) {
        for(int i = 0; i < k; i++){
            roateNums(nums);
        }
    }

    void roateNums(int[] nums){
        int temp;
        int pre = nums[nums.length - 1];
        for(int i = 0; i < nums.length; i++){
            temp = nums[i];
            nums[i] = pre;
            pre = temp;
        }
    }

使用环状替换

  • 把一个在i位置上元素向后旋转k个元素,那么它的位置应该为next = (i + k) % length

    拿到一个元素,找到它的位置,然后拿到被替换的元素,再找它的位置,一直替换下去,代码如下

    代码如下

    while(next != current){
        next = (current + k) % len;
        int temp = nums[next];
        nums[next] = prev;
        prev = temp;
        current = next;
        count++;
    }
    
  • 看上去很美好,一直这样轮换不就可以了吗,但是这样仅仅适用于klength的最大公约数为1的情况,当不为1时,例如n=24, k=14时, 其最大公约数为2, 这一个替换只能替换一部分的元素,剩下的一部分元素一直不会被移动。

  • 因此我们需要做一个判断,判断什么呢,对于n个元素,需要移动n次就够了,判断移动次数是否到n,如果为到n的时候while循环结束了,说明这些元素是一个循环,我们应该换一个元素,再进行移位,直至移动次数到n次结束

代码如下

    public void rotate(int[] nums, int k) {
        int len = nums.length;
        int count = 0;
        for(int start = 0; count < len; start++){
            int current = start;
            int prev = nums[start];

            do{
                int next = (current + k) % len;
                int temp = nums[next];
                nums[next] = prev;
                prev = temp;
                current = next;
                count++;
            }while(start != current);
        }
    }
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
posted @ 2020-11-10 17:35  水纸杯  阅读(103)  评论(0)    收藏  举报