Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

912. Sort an Array

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(nlog(n)) time complexity and with the smallest space complexity possible.

Example 1:

Input: nums = [5,2,3,1]
Output: [1,2,3,5]

Example 2:

Input: nums = [5,1,1,2,0,0]
Output: [0,0,1,1,2,5]

Merge sort (ping-pong buffer):

#![allow(unused)]
fn main() {
// time O(n log n), space O(n)
pub fn sort_array(mut nums: Vec<i32>) -> Vec<i32> {
    let mut scratch = nums.clone();
    merge_sort(&mut nums, &mut scratch);
    nums
}

fn merge_sort(dst: &mut [i32], scratch: &mut [i32]) {
    if dst.len() <= 1 {
        return;
    }

    let mid = dst.len() / 2;
    let (dst_left, dst_right) = dst.split_at_mut(mid);
    let (buf_left, buf_right) = scratch.split_at_mut(mid);

    merge_sort(buf_left, dst_left);
    merge_sort(buf_right, dst_right);

    merge(buf_left, buf_right, dst);
}

fn merge(left: &[i32], right: &[i32], out: &mut [i32]) {
    let (mut i, mut j, mut k) = (0, 0, 0);
    while i < left.len() && j < right.len() {
        if left[i] <= right[j] {
            out[k] = left[i];
            i += 1;
        } else {
            out[k] = right[j];
            j += 1;
        }
        k += 1;
    }

    out[k..].copy_from_slice(if i < left.len() {
        &left[i..]
    } else {
        &right[j..]
    });
}
}

Counting sort:

#![allow(unused)]
fn main() {
// time O(n + range), space O(range)
pub fn sort_array_counting(mut nums: Vec<i32>) -> Vec<i32> {
    let Some((min, max)) = min_max(&nums) else {
        return nums;
    };

    let span = (max as i64 - min as i64 + 1) as usize;
    let mut cnt = vec![0u32; span];

    for &x in &nums {
        cnt[(x - min) as usize] += 1;
    }

    let mut k = 0;
    for (offset, &count) in cnt.iter().enumerate() {
        let count = count as usize;
        nums[k..k + count].fill(min + offset as i32);
        k += count;
    }

    nums
}

fn min_max(v: &[i32]) -> Option<(i32, i32)> {
    let mut it = v.iter().copied();
    let first = it.next()?;
    Some(it.fold((first, first), |(lo, hi), x| (lo.min(x), hi.max(x))))
}
}

Quicksort (randomized pivot, three-way partition):

#![allow(unused)]
fn main() {
// time O(n log n) expected, space O(log n) expected
pub fn sort_array_quicksort(mut nums: Vec<i32>) -> Vec<i32> {
    let mut rng = Rng::new();
    quicksort(&mut nums, &mut rng);
    nums
}

fn quicksort(v: &mut [i32], rng: &mut Rng) {
    if v.len() <= 1 {
        return;
    }

    let pivot = v[rng.below(v.len())];
    let (lt, gt) = partition(v, pivot);

    let (less, rest) = v.split_at_mut(lt);
    let (_equal, greater) = rest.split_at_mut(gt - lt);

    quicksort(less, rng);
    quicksort(greater, rng);
}

fn partition(v: &mut [i32], pivot: i32) -> (usize, usize) {
    let (mut lt, mut i, mut gt) = (0, 0, v.len());
    while i < gt {
        if v[i] < pivot {
            v.swap(lt, i);
            lt += 1;
            i += 1;
        } else if v[i] > pivot {
            gt -= 1;
            v.swap(i, gt);
        } else {
            i += 1;
        }
    }

    (lt, gt)
}

struct Rng(u64);

impl Rng {
    fn new() -> Self {
        Rng(RandomState::new().build_hasher().finish() | 1)
    }

    fn next_u64(&mut self) -> u64 {
        let mut x = self.0;
        x ^= x >> 12;
        x ^= x << 25;
        x ^= x >> 27;
        self.0 = x;
        x.wrapping_mul(0x2545_F491_4F6C_DD1D)
    }

    fn below(&mut self, n: usize) -> usize {
        ((self.next_u64() as u128 * n as u128) >> 64) as usize
    }
}
}