Sort an Array
Link
Description
Given an array of integers nums
, sort the array in ascending order and return it.
You must solve the problem without using any built-in functions in \(O(n\log n)\) time complexity and with the smallest space complexity possible.
Example 1:
- Input:
nums = [5,2,3,1]
- Output:
[1,2,3,5]
- Explanation:
After sorting the array, the positions of some numbers are not changed (for example, 2 and 3), while the positions of other numbers are changed (for example, 1 and 5).
Example 2:
- Input:
nums = [5,1,1,2,0,0]
- Output:
[0,0,1,1,2,5]
- Explanation:
Note that the values of nums are not necessairly unique.
Constraints:
1 <= nums.length <= 5 * 10^4
-5 * 10^4 <= nums[i] <= 5 * 10^4
Solution
Merge Sort
Recursive Version
| class Solution {
private:
vector<int> temp;
void mergeSort(vector<int>& nums, int left, int right) {
if (left >= right) return;
int mid = (left + right) >> 1;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
mergeOperation(nums, left, mid, right);
}
void mergeOperation(vector<int>& nums, int left, int mid, int right) {
int k = 0, i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) temp[k++] = nums[i++];
else temp[k++] = nums[j++];
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
for (i = left, j = 0; i <= right; i++, j++) nums[i] = temp[j];
}
public:
vector<int> sortArray(vector<int>& nums) {
temp.resize(nums.size());
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
};
|
- Time complexity: \(O(n\log n)\);
- Space complexity: \(O(\log n)\) for recursive approach.
Iterative Version
| class Solution {
private:
vector<int> temp;
void mergeSort(vector<int>& nums) {
int n = nums.size();
for (int left, mid, right, step = 1; step < n; step <<= 1) {
left = 0;
while (left < n) {
mid = left + step - 1;
if (mid + 1 >= n) break;
right = min(left + (step << 1) - 1, n - 1);
mergeOperation(nums, left, mid, right);
left = right + 1;
}
}
}
void mergeOperation(vector<int>& nums, int left, int mid, int right) {
int k = 0, i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) temp[k++] = nums[i++];
else temp[k++] = nums[j++];
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
for (i = left, j = 0; i <= right; i++, j++) nums[i] = temp[j];
}
public:
vector<int> sortArray(vector<int>& nums) {
temp.resize(nums.size());
mergeSort(nums);
return nums;
}
};
|
Quick Sort
| class Solution {
private:
void quick_sort(vector<int>& nums, int l, int r) {
if (l == r) return;
int i = l - 1, j = r + 1, x = nums[(l + r) >> 1];
while (i < j) {
do i++; while (nums[i] < x);
do j--; while (nums[j] > x);
if (i < j) swap(nums[i], nums[j]);
}
quick_sort(nums, l, j);
quick_sort(nums, j + 1, r);
}
public:
vector<int> sortArray(vector<int>& nums) {
quick_sort(nums, 0, nums.size() - 1);
return nums;
}
};
|
- Time complexity: average case \(O(n\log n)\), worst case \(O(n^2)\) (but we rarely reach the worst case);
- Space complexity: \(O(\log n)\).
Heap Sort
STL Version
| class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
priority_queue<int, vector<int>, greater<int>> q;
vector<int> res;
res.reserve(nums.size());
for (int i : nums) q.push(i);
while (!q.empty()) {
res.emplace_back(q.top());
q.pop();
}
return res;
}
};
|
Array Version
Min Heap
| class Solution {
private:
vector<int> h;
int cnt;
void up(int u) {
if (u / 2 && h[u / 2] > h[u]) {
swap(h[u], h[u / 2]);
up(u / 2);
}
}
void down(int u) {
int v = u;
if (2 * u <= cnt && h[2 * u] < h[v]) v = 2 * u;
if (2 * u + 1 <= cnt && h[2 * u + 1] < h[v]) v = 2 * u + 1;
if (u != v) {
swap(h[u], h[v]);
down(v);
}
}
void push(int x) {
h[++cnt] = x;
up(cnt);
}
void pop() {
h[1] = h[cnt--];
down(1);
}
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
h = vector<int>(n + 1, 0);
cnt = nums.size();
for (int i = 1; i <= n; i++) h[i] = nums[i - 1];
for (int i = n / 2; i; i--) down(i);
vector<int> res;
res.reserve(n);
while (n--) {
res.emplace_back(h[1]);
pop();
}
return res;
}
};
|
Max Heap
Iterative Solution:
| class Solution {
private:
// Adjust the number at position i upwards to maintain the max heap
// arr[i] = x, x is new! Look upwards until it's no longer larger than its parent, or reaches the top (0 position)
void heapInsert(vector<int>& nums, int i) {
while (nums[i] > nums[(i - 1) / 2]) {
swap(nums[i], nums[(i - 1) / 2]);
i = (i - 1) / 2;
}
}
// The number at position i has decreased, but we still want to maintain the max heap structure
// Adjust downwards to maintain the max heap
// The current size of the heap is "size"
void heapify(vector<int>& nums, int i, int size) {
int left = 2 * i + 1;
while (left < size) {
// There's a left child, left
// and a right child, left + 1
// Choose the "stronger" child
int largest = (left + 1 < size && nums[left + 1] > nums[left]) ? left + 1 : left;
// After choosing the "stronger" child,
// compare the current number with the strongest child to find the largest index
largest = nums[largest] > nums[i] ? largest : i;
if (largest == i) break;
swap(nums[i], nums[largest]);
i = largest;
left = 2 * i + 1;
}
}
public:
vector<int> sortArray(vector<int>& nums) {
vector<int> arr = nums;
int n = arr.size();
// Method 1: builds the heap from top to bottom and then sorts
// Build a max heap from top to bottom, O(n * logn)
// Sequentially pop the maximum value in the heap and sort, O(n * logn)
// Overall time complexity O(n * logn)
// for (int i = 0; i < n; i++) {
// heapInsert(arr, i);
// }
// Method 2: builds the heap from bottom to top and then sorts
// Build a max heap from bottom to top, O(n)
// Sequentially pop the maximum value in the heap and sort, O(n * logn)
// Overall time complexity O(n * logn)
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, i, n);
}
int size = n;
while (size > 1) {
swap(arr[0], arr[--size]);
heapify(arr, 0, size);
}
return arr;
}
};
|
Recursive Solution:
| class Solution {
private:
void heapInsert(vector<int>& nums, int i) {
if (i == 0) return;
int parent = (i - 1) / 2;
if (nums[i] > nums[parent]) {
swap(nums[i], nums[parent]);
heapInsert(nums, parent);
}
}
void heapify(vector<int>& nums, int i, int size) {
int left = 2 * i + 1, right = 2 * i + 2, largest = i;
if (left < size && nums[left] > nums[largest]) largest = left;
if (right < size && nums[right] > nums[largest]) largest = right;
if (largest != i) {
swap(nums[i], nums[largest]);
heapify(nums, largest, size);
}
}
public:
vector<int> sortArray(vector<int>& nums) {
vector<int> arr = nums;
int n = arr.size();
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, i, n);
}
for (int i = n - 1; i > 0; i--) {
swap(arr[0], arr[i]);
heapify(arr, 0, i);
}
return arr;
}
};
|