LC189. Rotate Array¶
Problem Description¶
LeetCode Problem 189: Given an array, rotate the array to the right by k
steps, where k
is non-negative.
Clarification¶
- Rotate to the right: fill the left with the elements coming out of the right
- \(k\) is non-negative
Assumption¶
Solution¶
There are 3 different approaches to solve the problem:
- Brute force using two loops to rotate the array
- Use additional array
- Reverse
Note that we have k = k % n
to handle the case where \(k >= n\).
Approach - Brute Force¶
The straightforward approach is to rotate all the elements of the array \(k\) times and each time move all elements to the right by \(1\) step.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
typedef vector<int>::size_type vec_size;
vec_size n = nums.size();
int temp;
for (int i = 0; i < k; i++) {
temp = nums[n-1];
for (vec_size j = n - 1; j >= 1; j--) {
nums[j] = nums[j-1];
}
nums[0] = temp;
}
}
};
Complexity Analysis¶
- Time complexity: \(O(n \times k)\)
It takes \(O(n)\) to shift all elements by one step. Since it is shifted \(k\) times, the time complexity is \(O(n \times k)\). - Space complexity: \(O(1)\)
Just use
temp
and indices with constant space.
Approach - Using Extra Array¶
We use an extra array to place element of the array at its correct position, i.e., the number at index i
in the original array is placed at the index (i + k) % length of array
in the new array. Then, copy the elements from the new array to the original one.
class Solution {
public:
void rotate(vector<int>& nums, int k) {
typedef vector<int>::size_type vec_size;
vec_size n = nums.size();
vector<int> aux(n);
// Save rotated array to the auxiliary array
for (vec_size i = 0; i < n; i++) {
aux[(i + k) % n] = nums[i];
}
// Copy the value back
for (vec_size i = 0; i < n; i++) {
nums[i] = aux[i];
}
}
};
Complexity Analysis¶
- Time complexity: \(O(n)\)
It takes \(O(n)\) to put the numbers in the new array and \(O(n)\) to copy the values to the original array. So the time complexity is \(O(n) = O(n) + O(n)\) - Space complexity: \(O(n)\) Needs a new array with the same size of the original array.
Approach - Reverse¶
The following approach is shared by @danny6514 and explained by @xingyze:
- Reverse all the elements of the array, "--->-->" to "<--<---"
- Reverse the first \(k\) elements "<--", we can get "--><---"
- Reverse the rest \(n-k\) elements "<---", we can get "-->--->"
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
k %= len(nums)
n = len(nums)
self.reverse(nums, 0, n - 1)
self.reverse(nums, 0, k - 1)
self.reverse(nums, k, n - 1)
def reverse(self, nums: List[int], start: int, end: int) -> None:
while start < end:
temp = nums[start]
nums[start] = nums[end]
nums[end] = temp
start += 1
end -= 1
class Solution {
public:
void rotate(vector<int>& nums, int k) {
vector<int>::size_type n = nums.size();
if (n <= 1) return; // k % 0 is undefined and no need to rotate for zero or 1 element
k = k % n; // make sure k is within [0, n)
// If no element to rotate or rotate 0 time, return
if (k < 1) return;
reverse(nums, 0, n - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}
private:
void reverse(vector<int>& nums, vector<int>::size_type begin, vector<int>::size_type end) {
while (begin < end) {
swap(nums[begin], nums[end]);
begin++;
if (end == 0) {
break;
}
else {
end--;
}
}
}
};
Complexity Analysis¶
- Time complexity: \(O(n)\)
The array is reversed total of two times. So the time complexity is \(O(n) = O(n) + O(n)\) - Space complexity: \(O(1)\) Just use some pointers of constant space.
Comparison of Different Approaches¶
The table below summarize the time complexity and space complexity of different approaches:
Approach | Time Complexity | Space Complexity |
---|---|---|
Approach - Brute Force | \(O(n \times k)\) | \(O(1)\) |
Approach - Use Extra Array | \(O(n)\) | \(O(n)\) |
Approach - Reverse | \(O(n)\) | \(O(1)\) |