旋转数组

[原题链接](初级算法 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台 (leetcode-cn.com))

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

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

三种解法

public class Solution {
    /**
     * 旋转数组(法一)
     * 思路:k取模后,将后k个元素暂存,然后将前length - k个元素复制到新的位置,
     * 最后填补前k个位置
     * 空间复杂度O(n),时间复杂度O(2n)
     * @param nums
     * @param k
     */
    public void rotate1(int[] nums, int k) {
        //取模,避免越界
        k = k % nums.length;
        int[] temp = new int[k];
        //暂存后k个元素
        for (int i = 0; i < k; i++) {
            temp[k - 1 - i] = nums[nums.length - 1 - i];
        }
        //将前length - k个元素复制到新的位置
        for (int i = nums.length - 1 - k; i >= 0; i--) {
            nums[i + k] = nums[i];
        }
        //填补前k个位置
        for (int i = 0; i < k; i++) {
            nums[i] = temp[i];
        }
    }

    /**
     * 法二:
     * 思路:经观察,旋转一次(原地)很容易做到,不妨循环执行k次旋转操作
     * 空间复杂度O(1),时间复杂度O(n^2)超时
     * @param nums
     * @param k
     */
    public void rotate2(int[] nums, int k){
        //取模,减少循环次数
        k = k % nums.length;
        if (k == 0 || nums.length == 1) return;
        for (int i = 0; i < k; i++) {
            rotateOnce(nums);
        }
    }

    private void rotateOnce(int[] nums){
        if(nums.length == 1) return;
        int temp = nums[nums.length - 1];
        //亦步亦趋
        for (int i = nums.length - 1; i > 0; i--) {
            nums[i] = nums[i - 1];
        }
        nums[0] = temp;
    }

    /**
     * 法三:
     * 思路:翻转,先翻转整个数组,这样“两个整体的顺序”是正确的,不过局部是逆序的
     * 然后翻转前k个元素,使得前k个元素顺序正确;翻转后k - 1个元素,使得后k - 1个元素顺序正确
     * 空间复杂度O(1),时间复杂度O(n)
     * @param nums
     * @param k
     */
    public void rotate3(int[] nums, int k){
        k = k % nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
    }

    /**
     * 翻转数组
     * 参数:start起始位置, end结束位置
     * @param nums
     * @param start
     * @param end
     */
    private void reverse(int[] nums, int start, int end) {
        int temp = 0;
        while(end > start){
            temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            end--;
            start++;
        }
    }
}

    不难看出,比起法一和法二,法三无论是空间上(O(1))还是时间上(O(n))都更优。