题目如下:
Rotate an array of n elements to the right by k steps.
For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
Note:
Do it in place.Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
分析如下:
注意是要in place来完成这个问题,也就是空间复杂度是O(1)。
比较容易想到的办法是,逐步挪动,挪动N(假设数组长度为N)次之后,就完成了rotate。 但是这样可能会有的元素挪动了不止一次,有的元素完全没有动过。
例如,下面这个错误解法
从第5步开始,就和之前的步骤完全一样不会发生改变了。
//错误解法 class Solution { public: //(1): 1 2 3 4 5 6 //(2): 1 2 1 4 5 6 //(3): 1 2 1 4 3 6 //(4): 5 2 1 4 3 6 //(5): 5 2 1 4 3 6 //(6): 5 2 1 4 1 6 //(7): 3 2 1 4 1 6 //(8): 3 2 1 4 1 6 //(9): 形成了环 void rotate(int nums[], int n, int k) { int start = 0; int tmp2 = 0; int tmp1 = nums[start]; int count = n; while(count > 0) { tmp2 = nums[(start + k ) % n]; nums[(start + k ) % n] = tmp1; tmp1 = tmp2; start = (start + k) % n; --count; print_list(nums, n); } } };
第一种正确的做法
很神奇, 在programming pearl上有介绍到,一共有3步。假设输入数组的下标是0~ n-1,需要rotate的步数是k.
step 1 reverse原来的数组
step 2 reverse 0~ k-1
step 3 reverse k ~ n-1
我的代码:
//38ms class Solution { public: void reverseString(int nums[], int start, int end) { int i = start; int j = end; int temp = 0; while (i<j) { temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; ++i; --j; } return; } void rotate(int nums[], int n, int k) { k = k % n; reverseString(nums, 0, n - 1); reverseString(nums, 0, k - 1); reverseString(nums, k, n - 1); } };
上面的时间复杂度是O(n),空间复杂度是O(1).
另外一个解法
一步一步地挪动,具体解答如下:
初始数组:1, 2, 3, 4, 5, 6
右移一步: 6, 1, 2, 3, 4, 5
右移二步: 5, 6, 1, 2, 3, 4
...
右移五步: 2, 3, 4, 5, 6, 1
如果k< n/2,那么就逐步向右移动 k步,否则就向左移动n - k 步。
//383ms class Solution { public: void print_list(int* a, int n){ for (int i = 0; i < n; ++i) { std::cout<<a[i]<<"\t"; } std::cout<<std::endl; return; } void MoveRightByOne(int nums[], int n) { int temp = nums[ n - 1]; for (int i = n - 1; i >=1 ; --i) { nums[i] = nums[i - 1]; } nums[0] = temp; } void MoveLeftByOne(int nums[], int n) { int temp = nums[0]; for (int i = 0; i < n-1 ; ++i) { nums[i] = nums[i + 1]; } nums[n - 1] = temp; } void rotate(int nums[], int n, int k) { k = k % n; // NOTE: validate input,容易漏想。 if (k < n/2) { for (int i = 0; i < k; ++i) { MoveRightByOne(nums, n); } } else { for (int i = 0; i < n-k; ++i) { MoveLeftByOne(nums, n); } } } };
参考资料:
//http://articles.leetcode.com/2010/04/rotating-array-in-place.html