GuilinDev

Lc0189

05 August 2008

189 Rotate Array

原题概述

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

Example 1:

1
2
3
4
5
6
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:

1
2
3
4
5
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]

题意和分析

翻转数组右边部分k个元素,如果可以用辅助数组,就直接 (i + k) % n来映射就行了,但是要求空间为常量,所以用额外数组来做不满足要求

1)用辅助变量来记录数组元素,将上面的解法要被替换的元素不直接放在最后的位置,而用一个temp来记录;2)数组翻转,先翻转整个数组,再翻转前k个数字,最后翻转后len - k个数字;

代码

每一次移动都将数组中的一个元素 nums[i] 移动到 k 个位置后, 即 nums[(i+k)%n] ,将(i+k)%n 记为pos), 这个时候会出现元素覆盖问题,需要一个临时变量 temp 保存被覆盖的元素, 再将覆盖的元素用 pre 做记录,每次只需讲 pre 赋值给 nums[pos], 更新 pre 为被覆盖的元素,再寻找 nums[pos] 的下一个 元素 (pos+k)%n,直到所有元素都移动,即移动了n次(一共n个元素,每个都需要移动一次)

此时会存在一个问题,当 k 为 n 的因子时,会出现循环情况,例如 从 0 开始移动数组,最终会再回到0,而无法对其他的元素进行修改;此时只需要从 i=0 的下一个元素,即 i=1 开始移动数组元素即可,可以证明不会出现重叠的情况,只需循环到 i==k 时,即终止循环,nums 所有的元素移动完毕。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
    public void rotate(int[] nums, int k) {
        int len = nums.length,n = len;
        int i = 0,pos = 0, pre = nums[pos],temp = nums[pos];

        if(k % n == 0) return;

        while (n-- != 0) {
            pos =  (pos + k) % len;
            temp = nums[pos];
            nums[pos] = pre;
            pre = temp;
            if (pos == i) {
                pos = ++i;
                pre = nums[pos];
                temp = nums[pos];
            }
        }
    }
}

数组翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
    public void rotate(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return;
        }

        k %= nums.length;//k有可能比数组长度长

        int len = nums.length;

        reverse(nums, 0, len - 1);//全部数组翻转一遍
        reverse(nums, 0, k - 1);//翻转前k个数组元素,翻转的目标范围
        reverse(nums, k, len - 1);//翻转后面len - k个元素
    }
    private void reverse(int[] nums, int left, int right) {
        while (left < right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            left++;
            right--;
        }
    }
}