Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input: [1,2,3,4,5,6,7] and k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Example 2:
Input: [-1,-100,3,99] and k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]
Note:
Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
Could you do it in-place with O(1) extra space?
这题有多种解法,其中时间复杂度O(n2)和空间复杂度O(n)的就不讲了,比较简单。我想讲的是时间复杂度O(n)和空间复杂度O(1)的解法。
解法1:
最简单的是直接使用STL函数rotate(beg, newBeg, end)。
C++代码如下:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k %= n;
std::rotate(nums.begin(), nums.begin()+n-k, nums.end());
}
};
解法2:
比上面稍微复杂点,需要3步。
第1步,将前n-k个元素反转次序,为了省事我还是使用STL的函数reverse(beg, end)来实现反转;
第2步,将剩下k个元素反转次序;
最后一步,对整个数组反转次序。这样就可以得到我们需要的结果了。
如下所示:
输入:[1,2,3,4,5,6,7] and k = 3
第1步: [4,3,2,1,5,6,7]
第2步:[4,3,2,1,7,6,5]
第3步:[5,6,7,1,2,3,4]
C++代码如下:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
k %= n;
reverse(nums.begin(), nums.begin()+n-k);
reverse(nums.begin()+n-k, nums.end());
reverse(nums.begin(), nums.end());
}
};
解法3:
上面两种方法都比较好理解,一看就知道怎么回事。这第3种方法通过两两交换来实现我想了好长时间,直觉感觉两两交换肯定可以实现,但就是当剩余的没交换长度小于k以后就不知道该怎么处理了。当时就卡在这里,不知如何进行。现在我们来想一下,假如k等于数组长度,那么结果会怎样?我们发现经过旋转数组回到了最初状态,没有变化,刚好旋转了一个周期。由此,我们可以想到如果k大于数组的长度,其实旋转的只是k减去数组长度以后多余的部分,也就是说我们需要旋转的只是k%nums.size()部分,这样就全弄懂了。我们通过两两交换先将k%nums.size()个元素完成交换,然后去掉已经交换的部分,剩下的部分继续通过两两交换将k%n个元素完成交换,直到n为0。
过程如下所示:
输入:[1,2,3,4,5,6,7] and k = 3
首先,第1个元素和第n-k个元素交换,即:1和5,2和6,3和7分别交换,得到[5,6,7,4,1,2,3],去掉已经完成交换元素可以得到[4,1,2,3],剩下数组长度n = nums.size() - k,k = k%n。
然后,继续将剩下数组的第1个和第n-k个元素交换,即:4和1,4和2,4和3分别交换,得到[1,2,3,4],剩下数组长度n=n-k=1,k=k%n=0,完成交换。
C++代码如下:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
for(int j = 0; k %= n; n -= k){
for(int i = 0; i < k; i++, j++){
swap(nums[j], nums[j+n-k]);
}
}
}
};
Python的实现我就直接使用切片大法,切片是个好东西。对数组的操作Python真是比C++方便太多了。
Python代码如下:
class Solution:
def rotate(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: void Do not return anything, modify nums in-place instead.
"""
n = len(nums);
k %= n
nums[:] = nums[n-k:] + nums[:n-k]