文章目录
189. 旋转数组
题目来源
题目分析
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
题目难度
- 难度:中等
题目标签
- 标签:数组、数学、双指针
题目限制
1 <= nums.length <= 10^5-2^31 <= nums[i] <= 2^31 - 10 <= k <= 10^5
解题思路
思路1:数组拷贝
- 问题定义:
- 将数组中的元素向右移动 k 个位置,可以通过创建一个新数组来实现。
- 核心算法:
- 计算每个元素在新数组中的位置,即
(i + k) % nums.length。 - 将原数组中的元素复制到新数组的正确位置。
- 最后将新数组的元素复制回原数组。
- 计算每个元素在新数组中的位置,即
思路2:反转
- 问题定义:
- 通过反转数组的三部分来实现旋转。
- 核心算法:
- 反转整个数组。
- 反转前 k 个元素。
- 反转剩余的元素。
核心算法步骤
数组拷贝
- 初始化新数组:
- 创建一个与原数组长度相同的新数组
ans。
- 创建一个与原数组长度相同的新数组
- 计算新位置并复制元素:
- 遍历原数组
nums,将每个元素放置到新数组ans的正确位置。
- 遍历原数组
- 复制回原数组:
- 使用
System.arraycopy将新数组的元素复制回原数组。
- 使用
反转
- 反转整个数组:
- 调用
reverse函数反转整个数组。
- 调用
- 反转前 k 个元素:
- 调用
reverse函数反转数组的前 k 个元素。
- 调用
- 反转剩余元素:
- 调用
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) 的解法。
2165

被折叠的 条评论
为什么被折叠?



