leetcode 189. 旋转数组

189. 旋转数组

难度:简单java

题库地址:leetcode-cn.com/problems/ro…算法

1. 题目描述

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

示例 1:bash

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

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

说明:.net

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

2. 解题思路

英文版的有答案:leetcode.com/problems/ro…3d

这里记录一下第4种方法的理解:Approach #4 Using Reverse [Accepted]code

假设对长度为 n 的数组,进行 k 次旋转。leetcode

首先要找到最终有效的次数,由于旋转的循环的,当对数组进行 n 次旋转时,至关于没有对数组进行操做,同时该方法必须先找到最终有效次数,不然无法对数组进行镜像操做。get

为何在不一样位置采用三次镜像操做就能实现数组的 k 次旋转,连同答案和本身的理解整理为以下:

  1. 先计算 k 的有效次数,由于旋转是循环进行的,像自行车链条同样,当元素旋转一整圈即:k = n 时,全部元素回到了原来的位置,因此 k 次旋转的有效次数为 k \% n

  2. 咱们将数组以 n 为边界拆分红两部分看待,前 n-k 个元素部分:S_1 = \{t_1,t_2,...,t_{n-k}\} 和 后 n 个元素部分 S_2 = \{t_{n-k+1},t_{n-k+2},...,t_n\}为何以 k 为分界点呢?由于对数组进行 k 次旋转后,S_1S_2 将互换位置。 如数组:\{1,2,3,4,5,6\},长度 n = 6,进行 k=2 次旋转,对应 S_1 = \{1, 2, 3, 4\}S_2 = \{5,6\},旋转结束后获得数组: S_2 = \{5, 6\}S_1 = \{1, 2, 3, 4\}

  3. 为了实现将 S_1S_2 位置互换,这里采用将整个数组镜像的策略。 原元素:\{1,2,3,4,5,6\} 镜像后:\{6, 5, 4, 3, 2, 1\}

  4. 对数组进行镜像操做后,虽然 S_1S_2 位置互换,可是其内部元素也被镜像了,为了将 S_1S_2 内部元素的顺序恢复,对 S_1S_2 再分别进行一次镜像。

    举例以下原数组:\{1,2,3,4,5,6\} 镜像前: S_1 = \{1, 2, 3, 4\}S_2 = \{5,6\} 镜像后:S_2 = \{6,5\}S_1 = \{4, 3, 2, 1\}S_1S_2 分别进行一次镜像后获得的最终结果:S_2 = \{5, 6\}S_1 = \{1, 2, 3, 4\} 最终答案:\{5, 6, 1, 2, 3, 4\}

    算法思想再精简一点以下:

    1. 对数组以 k 划分红两部分,分为前 n-k 个元素部分,和后 k 个部分,这样划分的目的是旋转 k 次后这两部分正好位置互换。
    2. 为了实现这种位置互换须要将数组镜像
    3. 镜像虽然将两部分数据总体的位置转换了过来,可是两部分数组内部数据顺序错误,须要对两部分数组分别镜像

Java实现:

class Solution {
    public void rotate(int[] nums, int k) {
        if (nums == null || nums.length < 2) {
            return;
        }
        // 计算有效旋转次数
        k %= nums.length;
        // 对整个数组镜像,使 S2 和 S1 位置互换
        reverse(nums, 0, nums.length - 1);
        // 对 S2 镜像处理,使其内部元素顺序恢复
        reverse(nums, 0, k - 1);
        // 对 S1 镜像处理,使其内部元素顺序恢复
        reverse(nums, k, nums.length - 1);
    }

    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[end];
            nums[end] = nums[start];
            nums[start] = temp;
            start++;
            end--;
        }
    }
}
复制代码
相关文章
相关标签/搜索