本题来自 LeetCode:189. 旋转数组[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) 的 原地 算法。
解法一 向后移动
题目分析
可以采用向后移动的方式解决。
一共需要向后移动
k
次,每次将尾节点移到首节点,将位置
[0...n-2]
依次移到位置
[1...n-1]
。
题目解答
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0) {
return;
}
int n = nums.length;
k = k % n;
if(k == 0) {
return;
}
// 向后移动k次,每次将尾节点移到首节点,将位置[0...n-2]依次移到位置[1...n-1]
for(int i = 0; i k; i ++) {
int temp = nums[n - 1];
for(int j = n - 1; j 0; j --) {
nums[j] = nums[j - 1];
}
nums[0] = temp;
}
}
}
复杂度分析:
时间复杂度:
O((k % n)* n)
空间复杂度:
O(1)
解法二 向前移动
题目分析
也可以采用向前移动的方式解决。
一共需要向前移动
n - k
次,每次将首节点移到尾节点,将位置
[1...n-1]
依次移到位置
[0...n-2]
。
题目解答
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0) {
return;
}
int n = nums.length;
k = k % n;
if(k == 0) {
return;
}
// 向前移动n - k次,每次将首节点移到尾节点,将位置[1...n-1]依次移到位置[0...n-2]
for(int i = 0; i n - k; i ++) {
int temp = nums[0];
for(int j = 0; j n - 1; j ++) {
nums[j] = nums[j + 1];
}
nums[n - 1] = temp;
}
}
}
复杂度分析:
时间复杂度:
O((k % n)* n)
空间复杂度:
O(1)
解法三
题目分析
为了使元素总的移动次数最少,可以结合前面两种解法来解答。
题目解答
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0) {
return;
}
int n = nums.length;
k = k % n;
if(k == 0) {
return;
}
if(k n - k) {
// 向前移动n - k次,每次将首节点移到尾节点,将位置[1...n-1]依次移到位置[0...n-2]
for(int i = 0; i n - k; i ++) {
int temp = nums[0];
for(int j = 0; j n - 1; j ++) {
nums[j] = nums[j + 1];
}
nums[n - 1] = temp;
}
return;
}
// 向后移动k次,每次将尾节点移到首节点,将位置[0...n-2]依次移到位置[1...n-1]
for(int i = 0; i k; i ++) {
int temp = nums[n - 1];
for(int j = n - 1; j 0; j --) {
nums[j] = nums[j - 1];
}
nums[0] = temp;
}
}
}
复杂度分析:
时间复杂度:
O((k % n)* n)
空间复杂度:
O(1)
解法四 反转法
题目分析
我们也可以分成三步来解决
以示例 1 为例,原数组为
[1,2,3,4,5,6,7]
。
k = 3
。
1. 反转子数组[0, 3]
[4, 3, 2, 1, 5, 6, 7]
2. 反转子数组[4, 6]
[4, 3, 2, 1, 7, 6, 5]
3. 反转子数组[0, 6]
[5, 6, 7, 1, 2, 3, 4]
题目解答
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0) {
return;
}
int n = nums.length;
k = k % n;
if(k == 0) {
return;
}
// 反转子数组[0, n -k - 1]
reverse(nums, 0, n - k - 1);
// 反转子数组[n -k, n - 1]
reverse(nums, n - k, n - 1);
// 反转数组[0, n - 1]
reverse(nums, 0, n - 1);
}
public void reverse(int[] nums ,int begin, int end) {
while(begin end) {
swap(nums, begin ++, end --);
}
}
public void swap(int[] nums ,int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
复杂度分析:
时间复杂度:
O(n)
空间复杂度:
O(1)
参考资料
原文始发于微信公众号(xiaogan的技术博客):