LeetCode 189. 旋转数组 Java实现

189. 旋转数组

题目来源

189. 旋转数组

题目分析

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

题目难度

  • 难度:中等

题目标签

  • 标签:数组、数学、双指针

题目限制

  • 1 <= nums.length <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1
  • 0 <= k <= 10^5

解题思路

思路1:数组拷贝

  1. 问题定义
    • 将数组中的元素向右移动 k 个位置,可以通过创建一个新数组来实现。
  2. 核心算法
    • 计算每个元素在新数组中的位置,即 (i + k) % nums.length
    • 将原数组中的元素复制到新数组的正确位置。
    • 最后将新数组的元素复制回原数组。

思路2:反转

  1. 问题定义
    • 通过反转数组的三部分来实现旋转。
  2. 核心算法
    • 反转整个数组。
    • 反转前 k 个元素。
    • 反转剩余的元素。

核心算法步骤

数组拷贝
  1. 初始化新数组
    • 创建一个与原数组长度相同的新数组 ans
  2. 计算新位置并复制元素
    • 遍历原数组 nums,将每个元素放置到新数组 ans 的正确位置。
  3. 复制回原数组
    • 使用 System.arraycopy 将新数组的元素复制回原数组。
反转
  1. 反转整个数组
    • 调用 reverse 函数反转整个数组。
  2. 反转前 k 个元素
    • 调用 reverse 函数反转数组的前 k 个元素。
  3. 反转剩余元素
    • 调用 reverse 函数反转数组的剩余元素。

代码实现

以下是旋转数组的 Java 代码实现:

public void rotate(int[] nums, int k) {
    // 方法1:数组拷贝
    int[] ans = new int[nums.length];
    for (int i = 0; i < nums.length; i++) {
        ans[(i + k) % nums.length] = nums[i];
    }
    System.arraycopy(ans, 0, nums, 0, nums.length);
    // 方法2:反转
    k %= nums.length;
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
}
public void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

代码解读

  • 数组拷贝:通过创建新数组并计算每个元素的新位置来实现旋转。
  • 反转:通过三次反转操作来达到旋转数组的目的。

性能分析

  • 时间复杂度O(n),其中 n 是数组 nums 的长度。无论是数组拷贝还是反转,每个元素都只被处理一次。
  • 空间复杂度O(n),用于存储新数组的额外空间(对于数组拷贝方法)。

测试用例

你可以使用以下测试用例来验证代码的正确性:

public static void main(String[] args) {
    int[] nums = {1, 2, 3, 4, 5, 6, 7};
    int k = 3;
    rotate(nums, k);
    System.out.println(Arrays.toString(nums)); // 输出: [5, 6, 7, 1, 2, 3, 4]
}

扩展讨论

有没有其他方法可以解决这个问题?

  • 循环移动:可以尝试每次只移动一个元素,直到移动 k 次,但这种方法的时间复杂度较高。

总结

本题通过数组拷贝和反转两种方法有效地解决了数组旋转的问题,提供了两种时间复杂度为 O(n) 的解法。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值