189 旋转数组
题目描述
题目链接
给定一个数组,将数组中的元素向右移动 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]
方法一 额外数组空间
采用额外的数组空间实现,时间复杂度和空间复杂度结尾O(n)
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
int[] ans = new int[len];
int j = 0;
for(int i=len-k; i<len; i++){
ans[j++] = nums[i];
}
for(int i=0; i<len-k; i++)
ans[j++] = nums[i];
for(int i=0; i<len; i++)
nums[i] = ans[i];
}
}
方法二 暴力法
旋转k次,每次将数组旋转1个元素。
时间复杂度为O(n*k),空间复杂度为O(1)。
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
int pre,temp;
for(int i=0; i<k; i++){
pre = nums[len-1];
for(int j=0;j<len;j++){
temp = nums[j];
nums[j] = pre;
pre = temp;
}
}
}
}
方法三 三次反转
首先将数组逆序,然后将前k个元素和后面的元素分别反转。
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4 --> 结果
时间复杂度为O(n),空间复杂度为O(1)
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
reverse(nums, 0, len-1);
reverse(nums, 0, k-1);
reverse(nums, k, len-1);
}
private void reverse(int[] nums, int start, int end){
while(start < end){
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start ++;
end--;
}
}
}
方法四 环状替换
参考自:https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode/
思路: 类似于换座位(座位号就是下标),第1个同学离开座位去了第k+1个座位,那么第k+1座位的原学生就被挤出去了,他要移到他后面的第k个位置上,如此往复。
但需要注意,假如有一位同学被挤开到了第一个位置(没人的位置),此时没有学生被挤开,那么就需要顺着让第二位同学开始换位置。用count计数换了多少次座位(有多少人就换多少次)。
时间复杂度为O(n),空间复杂度为O(1)。
class Solution {
public void rotate(int[] nums, int k) {
int len = nums.length;
k = k % len;
int count = 0;
for(int start=0; count<len; start++){
int cur = start;
int pre = nums[cur];
do{
//将当前cur放到它的最终位置
int next = (cur + k) % len;
int temp = nums[next];
nums[next] = pre;
pre = temp;
cur = next;//更新cur
count++;
}while(start != cur);
}
}
}