Rust——leetcode_剑指 Offer 40. 最小的k个数

使用最大堆的优先队列,解决最小的k个数问题
最大堆优先队列先存储前k个元素,遍历剩下的元素,如果元素比队首元素小,就入队,否则忽略
最终队列存储了最小的k个数

impl Solution {
    pub fn get_least_numbers(arr: Vec<i32>, k: i32) -> Vec<i32> {
        let mut queue = PriorityQueue::new_priority();
        for i in 0..k {
            queue.enqueue(arr[i as usize])
        }
        for i in k..arr.len() as i32 {
            if let Some(d) = queue.get_front() {
                if !queue.is_empty() && arr[i as usize] < d {
                    queue.dequeue();
                    queue.enqueue(arr[i as usize]);
                }
            }
        }
        return queue.max_heap.data.to_vec()
    }
}

trait Queue<E> {
    fn get_size(&self) -> usize;
    fn is_empty(&self) -> bool;
    fn enqueue(&mut self, e: E);
    fn dequeue(&mut self) -> Option<E>;
    fn get_front(&self) -> Option<E>;
}

struct PriorityQueue<E: PartialOrd + Copy> {
    max_heap: MaxHeap<E>
}

impl<E: PartialOrd + Copy> PriorityQueue<E> {
    fn new_priority() -> PriorityQueue<E> {
        Self {
            max_heap: MaxHeap::new_max_heap()
        }
    }
}

impl<E: PartialOrd + Copy> Queue<E> for PriorityQueue<E> {
    fn get_size(&self) -> usize {
        self.max_heap.get_size()
    }

    fn is_empty(&self) -> bool {
        self.max_heap.is_empty()
    }

    fn enqueue(&mut self, e: E) {
        self.max_heap.add(e)
    }

    fn dequeue(&mut self) -> Option<E> {
        self.max_heap.extract_max()
    }

    fn get_front(&self) -> Option<E> {
        self.max_heap.find_max()
    }
}

pub struct MaxHeap<E: PartialOrd + Copy> {
    data: Vec<E>
}

impl<E: PartialOrd + Copy> MaxHeap<E> {
    pub fn new_max_heap() -> MaxHeap<E> {
        Self {
            data: Vec::new()
        }
    }

    pub fn new_max_heap_with_capacity(capacity: usize) -> MaxHeap<E> {
        Self {
            data: Vec::with_capacity(capacity)
        }
    }

    pub fn get_size(&self) -> usize {
        self.data.len()
    }

    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }
    // index索引的父节点
    fn parent(&self, index: usize) -> Option<usize> {
        if index == 0 {
            return None;
        }
        Some((index - 1) / 2)
    }

    fn left_child(&self, index: usize) -> usize {
        index * 2 + 1
    }
    fn right_child(&self, index: usize) -> usize {
        index * 2 + 2
    }

    // 维持完全二叉树,将添加的元素放到树的末尾,上浮操作,以满足最大堆的性质
    pub fn add(&mut self, e: E) {
        self.data.push(e);
        self.sift_up(self.data.len() - 1)
    }
    // 上浮
    // 和父节点比较,大于父节点,就交换位置
    fn sift_up(&mut self, mut index: usize) {
        // 父节点小于字节点
        while index > 0 {
            let res = self.parent(index);
            if let Some(p_ind) = res {
                if self.data.get(p_ind) < self.data.get(index) {
                    // swap
                    self.data.swap(index, p_ind);
                    index = p_ind;
                } else {
                    break;
                }
            } else {
                return;
            }
        }
    }

    pub fn find_max(&self) -> Option<E> {
        if self.data.len() == 0 {
            return None;
        }
        Some(self.data[0])
    }
    // 取出最大值,就是取出第一个元素,为了维持完全二叉树,将最后一个叶子节点,替换到第一个元素位置
    // 然后下沉操作,以满足最大堆的性质
    pub fn extract_max(&mut self) -> Option<E> {
        let res = self.find_max();
        let end_ind = self.data.len() - 1;
        // 将末尾元素提到根
        self.data.swap(0, end_ind);
        // 删除最后一个元素
        self.data.remove(end_ind);
        // 下沉
        self.sift_down(0);
        res
    }
    // 下沉
    // 左右子树比较,和最大的交换位置
    fn sift_down(&mut self, mut index: usize) {
        let res = self.left_child(index);
        //
        while self.left_child(index) < self.data.len() {
            let mut j = self.left_child(index);
            // 有右子节点,右节点元素大
            if j + 1 < self.data.len() && self.data.get(j + 1) > self.data.get(j) {
                j += 1;
            }
            // 此时j是最大值索引
            if self.data.get(index) > self.data.get(j) {
                break;
            }
            self.data.swap(index, j);
            index = j;
        }
    }

    // replace
    pub fn replace(&mut self, e: E) -> Option<E> {
        let res = self.find_max();
        // 替换
        self.data.insert(0, e);
        // 下沉
        self.sift_down(0);
        res
    }

    // 把数组进行堆化,O(n)复杂度
    // 从最后一个非叶子节点进行下沉
    pub fn heapify(&mut self, data: Vec<E>) -> bool {
        self.data = data;
        if self.data.len() != 1 {
            // 最后一个非叶子节点,就是最后一个叶子节点的父节点
            let mut p_ind = self.parent(self.data.len() - 1);
            match p_ind {
                None => false,
                Some(ind) => {
                    let mut i = ind as i32;
                    while i >= 0 {
                        self.sift_down(i as usize);
                        i -= 1;
                    }
                    true
                }
            };
        }
        return true;
    }
    // 根据传入的数组,转化最大堆,再排序
    pub fn sort(mut data: Vec<E>) -> MaxHeap<E> {
        if data.len() <= 1 {
            return Self { data };
        }
        // 最后一个叶子节点
        let index = data.len() - 1;
        // 父节点索引
        let p_ind = (index - 1) / 2;
        let mut i = p_ind as i32;
        while i >= 0 {
            let le = data.len();
            Self::sift_down_sort(&mut data, i as usize, le);
            i -= 1;
        }
        let mut j = (data.len() - 1) as i32;
        while j >= 0 {
            // 将最大值放到最后
            data.swap(0, j as usize);
            // 维持最大堆性质
            Self::sift_down_sort(&mut data, 0, j as usize);
            j -= 1;
        }
        Self {
            data
        }
    }
    // data[0,heap_ind)最大堆中,对索引index进行sift down
    fn sift_down_sort(data: &mut Vec<E>, mut index: usize, heap_ind: usize) {
        while 2 * index + 1 < heap_ind {
            let mut j = 2 * index + 1;
            // 有右子节点,右节点元素大
            if j + 1 < heap_ind && data.get(j + 1) > data.get(j) {
                j += 1;
            }
            // 此时j是最大值索引
            if data.get(index) > data.get(j) {
                break;
            }
            data.swap(index, j);
            index = j;
        }
    }
}

执行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值