概述
leetcode 189. 旋转数组
- 1. 题目描述
- 2. 解题思路
难度:简单
题库地址:https://leetcode-cn.com/problems/rotate-array/
1. 题目描述
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: [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:
输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 要求使用空间复杂度为 O(1) 的原地算法。
2. 解题思路
英文版的有答案:https://leetcode.com/problems/rotate-array/solution/
这里记录一下第4种方法的理解:Approach #4 Using Reverse [Accepted]
假设对长度为 n 的数组,进行 k 次旋转。
首先要找到最终有效的次数,因为旋转的循环的,当对数组进行 n 次旋转时,相当于没有对数组进行操作,同时该方法必须先找到最终有效次数,否则没法对数组进行镜像操作。
为什么在不同位置采用三次镜像操作就能实现数组的 k 次旋转,连同答案和自己的理解整理为如下:
-
先计算 k k k 的有效次数,因为旋转是循环进行的,像自行车链条一样,当元素旋转一整圈即: k = n k = n k=n 时,所有元素回到了原来的位置,所以 k k k 次旋转的有效次数为 k % n k % n k%n。
-
我们将数组以 n n n 为边界拆分成两部分看待,前 n − k n-k n−k 个元素部分: S 1 = { t 1 , t 2 , . . . , t n − k } S_1 = {t_1,t_2,...,t_{n-k}} S1={t1,t2,...,tn−k} 和 后 n n n 个元素部分 S 2 = { t n − k + 1 , t n − k + 2 , . . . , t n } S_2 = {t_{n-k+1},t_{n-k+2},...,t_n} S2={tn−k+1,tn−k+2,...,tn},为什么以 k k k 为分界点呢?因为对数组进行 k k k 次旋转后, S 1 S_1 S1 和 S 2 S_2 S2 将互换位置。
如数组: { 1 , 2 , 3 , 4 , 5 , 6 } {1,2,3,4,5,6} {1,2,3,4,5,6},长度 n = 6 n = 6 n=6,进行 k = 2 k=2 k=2 次旋转,对应 S 1 = { 1 , 2 , 3 , 4 } S_1 = {1, 2, 3, 4} S1={1,2,3,4}, S 2 = { 5 , 6 } S_2 = {5,6} S2={5,6},旋转结束后得到数组: S 2 = { 5 , 6 } S_2 = {5, 6} S2={5,6} , S 1 = { 1 , 2 , 3 , 4 } S_1 = {1, 2, 3, 4} S1={1,2,3,4} -
为了实现将 S 1 S_1 S1 和 S 2 S_2 S2 位置互换,这里采用将整个数组镜像的策略。
原元素: { 1 , 2 , 3 , 4 , 5 , 6 } {1,2,3,4,5,6} {1,2,3,4,5,6}
镜像后: { 6 , 5 , 4 , 3 , 2 , 1 } {6, 5, 4, 3, 2, 1} {6,5,4,3,2,1} -
对数组进行镜像操作后,虽然 S 1 S_1 S1 和 S 2 S_2 S2 位置互换,但是其内部元素也被镜像了,为了将 S 1 S_1 S1 和 S 2 S_2 S2 内部元素的顺序恢复,对 S 1 S_1 S1 和 S 2 S_2 S2 再分别进行一次镜像。
举例如下原数组: { 1 , 2 , 3 , 4 , 5 , 6 } {1,2,3,4,5,6} {1,2,3,4,5,6}
镜像前: S 1 = { 1 , 2 , 3 , 4 } S_1 = {1, 2, 3, 4} S1={1,2,3,4} , S 2 = { 5 , 6 } S_2 = {5,6} S2={5,6}
镜像后: S 2 = { 6 , 5 } S_2 = {6,5} S2={6,5} , S 1 = { 4 , 3 , 2 , 1 } S_1 = {4, 3, 2, 1} S1={4,3,2,1}
对 S 1 S_1 S1 和 S 2 S_2 S2 分别进行一次镜像后得到的最终结果: S 2 = { 5 , 6 } S_2 = {5, 6} S2={5,6} , S 1 = { 1 , 2 , 3 , 4 } S_1 = {1, 2, 3, 4} S1={1,2,3,4}
最终答案: { 5 , 6 , 1 , 2 , 3 , 4 } {5, 6, 1, 2, 3, 4} {5,6,1,2,3,4}算法思想再精简一点如下:
- 对数组以 k k k 划分成两部分,分为前 n − k n-k n−k 个元素部分,和后 k k k 个部分,这样划分的目的是旋转 k k k 次后这两部分正好位置互换。
- 为了实现这种位置互换需要将数组镜像
- 镜像虽然将两部分数据整体的位置转换了过来,但是两部分数组内部数据顺序错误,需要对两部分数组分别镜像
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--;
}
}
}
最后
以上就是勤恳金鱼为你收集整理的leetcode 189. 旋转数组的全部内容,希望文章能够帮你解决leetcode 189. 旋转数组所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复