力扣hot100:轮转数组(常规思路与三步反转讲解)(189)

轮转数组问题要求将数组元素向右移动 k 个位置,尾部元素移动到数组头部。本文讲解一种时间复杂度 O(n)、空间复杂度 O(1) 的优雅解法------三步反转算法。

问题描述

常见误区

正常思路
java 复制代码
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        int[] newArr = new int[n];
        for (int i = 0; i < n; ++i) {
            newArr[(i + k) % n] = nums[i];
        }
        System.arraycopy(newArr, 0, nums, 0, n);
    }
}

三步反转算法(最优解)

核心思想

通过三次反转实现轮转:

  1. 整体反转:将整个数组倒序排列。
  2. 反转前 k 个元素:恢复轮转后应位于数组头部元素的顺序。
  3. 反转剩余元素:恢复轮转后位于数组尾部的元素的顺序。
图解过程(以 nums = [1,2,3,4,5,6,7], k=3 为例)
步骤 操作 结果
原始数组 - [1,2,3,4,5,6,7]
整体反转(0 → n-1 首尾交换 [7,6,5,4,3,2,1]
反转前 k 个(0 → k-1 恢复头部顺序 [5,6,7,4,3,2,1]
反转剩余部分(k → n-1 恢复尾部顺序 [5,6,7,1,2,3,4]
️ 关键细节:处理 k 过大

k 超过数组长度,需取模:k = k % nums.length原因 :轮转 n 次后数组恢复原状,有效轮转次数为 k mod n

代码实现

java 复制代码
class Solution {
    public void rotate(int[] nums, int k) {
        k=k%nums.length;
        swap1(nums,0,nums.length-1);
        swap1(nums,0,k-1);
        swap1(nums,k, nums.length-1);
    }

    private void swap1(int[] nums, int i, int length) {

        while(i<length){

            int temp=nums[i];
            nums[i]=nums[length];
            nums[length]=temp;

            i++;
            length--;

        }

    }
}

⏱ 复杂度分析

步骤 时间复杂度 空间复杂度
整体反转 O(n) O(1)
k 个反转 O(k) O(1)
剩余部分反转 O(n-k) O(1)
总计 O(n) O(1)

对比额外空间解法(使用新数组): 时间复杂度 O(n),但空间复杂度 O(n)。

三步反转法是空间最优解。

总结

三步反转法的核心在于逆向思维:

  1. 整体反转打破原有顺序;
  2. 分段反转精准定位轮转后的子数组位置。 此方法高效且代码简洁,是解决数组轮转问题的首选方案。掌握后,类似旋转问题(如字符串旋转)均可触类旁通 。