8. Sort Array nlogn
8. Sort an Array
Quick Sort with 1 pivot: failed
→ worst O(n^2)
failed
→ worst O(n^2)Time: Time over
Space:
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function (nums) {
quickSort(nums, 0, nums.length - 1);
return nums;
};
function quickSort(arr, left, right) {
if (left >= right) {
return arr;
}
const pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
return arr;
}
function partition(arr, left, right) {
let pivot = right;
let pointer = left;
while (left < pivot) {
if (arr[left] < arr[pivot]) {
swap(arr, pointer, left);
pointer++;
console.log(pointer)
}
left++;
}
swap(arr, pointer, pivot);
return pointer;
}
function swap(arr, a, b) {
const temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
return arr;
}
Quick Sort with 2 pivots ⇒ good when duplicates
import java.util.Random;
class Solution {
private static Random random;
private static class Partition {
int left;
int right;
Partition() {}
Partition(int left, int right) {
this.left = left;
this.right = right;
}
}
public int[] sortArray(int[] nums) {
random = new Random(1);
Solution.quickSort(nums, 0, nums.length - 1);
return nums;
}
private static void quickSort(int[] nums, int start, int end) {
if (start < end) {
Partition partition = threeWayPartition(nums, start, end);
quickSort(nums, start, partition.left - 1);
quickSort(nums, partition.right + 1, end);
}
}
private static Partition threeWayPartition(int[] nums, int start, int end) {
int pivotIndex = start + random.nextInt(end - start + 1);
int pivotValue = nums[pivotIndex];
swap(nums, start, pivotIndex);
// Loop invariant:
// 1. [start, lt): strictly less than pivotValue
// 2. [lt, cur) : equal to pivotValue
// 3. [cur, gt] : unexplored
// 4. (gt, end] : strictly larger than pivotValue
int lt = start + 1;
int cur = start + 1;
int gt = end;
while(cur <= gt) {
if (nums[cur] < pivotValue) {
swap(nums, lt, cur);
lt++;
cur++;
} else if (nums[cur] == pivotValue) {
cur++;
} else if (nums[cur] > pivotValue) {
swap(nums, cur, gt);
gt--;
}
}
// At exit, the partition is [start, lt), [lt, gt], (gt, end].
return new Partition(lt, gt);
}
private static void swap(int[] nums, int i , int j) {
if (i == j)
return;
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
Merge Sort
Time: O(nlogn)
Space: O(N^2)
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
const arr = mergeSort(nums, 0, nums.length - 1);
return arr;
};
function mergeSort(arr, s, e) {
if ( s === e)
return [arr[s]];
const m = s + Math.floor((e - s) / 2);
const left = mergeSort(arr, s, m);
const right = mergeSort(arr, m + 1, e);
const merged = merge(left, right);
return merged;
}
function merge(arr1, arr2) {
let idx1 = 0;
let idx2 = 0;
const merged = [];
while (idx1 < arr1.length && idx2 < arr2.length) {
if (arr1[idx1] < arr2[idx2]) {
merged.push(arr1[idx1]);
idx1++;
} else {
merged.push(arr2[idx2]);
idx2++;
}
}
while (idx1 < arr1.length) {
merged.push(arr1[idx1]);
idx1++;
}
while (idx2 < arr2.length) {
merged.push(arr2[idx2]);
idx2++;
}
return merged;
}
function swap(arr, a, b) {
[arr[b], arr[a]] = [arr[a], arr[b]];
}
using temp array
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
const arr = mergeSort(nums, 0, nums.length - 1);
return arr;
};
function mergeSort(arr, s, e) {
if (s >= e) {
return arr;
}
const m = s + Math.floor((e - s) / 2);
mergeSort(arr, s, m);
mergeSort(arr, m + 1, e);
merge(arr, s, m, e);
return arr;
}
function merge(arr, left, mid, right) {
if (left >= right) {
return arr;
}
const len = right - left + 1;
const temp = new Array(len).fill(0);
let i = left;
let j = mid + 1;
let pointer = 0;
while (i <= mid && j <= right) {
if (arr[i] < arr[j]) {
temp[pointer] = arr[i];
i++;
} else {
temp[pointer] = arr[j];
j++;
}
pointer++;
}
while (i <= mid) {
temp[pointer] = arr[i];
i++;
pointer++;
}
while (j <= right) {
temp[pointer] = arr[j];
j++;
pointer++;
}
// replace
for (let i = 0; i < len; i++) {
arr[i + left] = temp[i];
}
// console.log(temp)
return arr;
}
function mergeSort1(arr, s, e) {
if ( s === e)
return [arr[s]];
const m = s + Math.floor((e - s) / 2);
const left = mergeSort(arr, s, m);
const right = mergeSort(arr, m + 1, e);
const merged = merge(left, right);
return merged;
}
function merge1(arr1, arr2) {
let idx1 = 0;
let idx2 = 0;
const merged = [];
while (idx1 < arr1.length && idx2 < arr2.length) {
if (arr1[idx1] < arr2[idx2]) {
merged.push(arr1[idx1]);
idx1++;
} else {
merged.push(arr2[idx2]);
idx2++;
}
}
while (idx1 < arr1.length) {
merged.push(arr1[idx1]);
idx1++;
}
while (idx2 < arr2.length) {
merged.push(arr2[idx2]);
idx2++;
}
return merged;
}
function swap(arr, a, b) {
[arr[b], arr[a]] = [arr[a], arr[b]];
}
Heap Sort
Time: buildHeap: O(nlogn) remove: O(logn)
Space: O(n)
/**
* @param {number[]} nums
* @return {number[]}
*/
var sortArray = function(nums) {
const minHeap = new Heap(nums);
const arr = [];
while (minHeap.heap.length !== 0) {
arr.push(minHeap.remove());
}
return arr;
};
class Heap {
constructor(arr, predicate = (a, b) => a <= b ? true : false) {
this.predicate = predicate;
this.heap = this.buildHeap(arr);
}
buildHeap(arr) {
let currentIndex = Math.floor((arr.length - 1 - 1) / 2);
while (currentIndex >= 0) {
this.siftDown(arr, currentIndex, arr.length - 1);
currentIndex--;
}
return arr;
}
insert(v) {
this.heap.push(v);
this.siftUp(this.heap, this.heap.length - 1);
}
remove(v) {
this.swap(this.heap, 0, this.heap.length - 1);
const elementToRemove = this.heap.pop();
this.siftDown(this.heap, 0, this.heap.length - 1);
return elementToRemove;
}
siftUp(heap, currentIndex) {
let parentIndex = Math.floor(( currentIndex - 1) / 2 );
while (parentIndex >= 0) {
if (this.predicate(heap[parentIndex], heap[currentIndex])) {
break;
}
this.swap(heap, parentIndex, currentIndex);
currentIndex = parentIndex;
parentIndex = Math.floor(( currentIndex - 1) / 2 );
}
}
siftDown(heap, currentIndex, endIndex) {
let left = currentIndex * 2 + 1;
while (left <= endIndex) {
let min = left;
const right = currentIndex * 2 + 2;
if (heap[right] !== undefined && this.predicate(heap[right], heap[min])) {
min = right;
}
const flag = this.predicate(heap[currentIndex], heap[min]);
if (flag) break;
this.swap(heap, currentIndex, min);
currentIndex = min;
left = currentIndex * 2 + 1;
}
}
swap(arr, a, b) {
[arr[b], arr[a]] = [arr[a], arr[b]];
}
}
Last updated