Skip to content
Go back

rust_practice_leetcode_problem_types





在 Rust 中,BinaryHeap 默认是最大堆(Max-Heap), 即堆顶(peek/pop 时获取的元素)始终是当前集合中的最大值。

self_inc.partial_cmp(&other_inc) 本身的比较方向是“从小到大”, 但配合 BinaryHeap(最大堆)使用时,会变成“从大到小”的最终效果!

如果要实现最小堆 --- 将 Ord 比较用 other.partial_cmp(self) 实现..

举例如下


#[derive(Debug, PartialEq)]
struct Class {
    pass: i32,  // 通过考试的学生人数
    total: i32,  // 班级总学生人数
}

impl Eq for Class{} 

impl PartialOrd for Class {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}


impl Ord for Class {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        let self_inc = (self.pass as f64 + 1.0) / (self.total  as f64 + 1.0) - (self.pass as f64) / (self.total as f64);
        let other_inc = (other.pass as f64 + 1.0) / (other.total  as f64 + 1.0) - (other.pass as f64) / (other.total as f64);

        self_inc.partial_cmp(&other_inc).unwrap_or(std::cmp::Ordering::Equal)
    }
}




🔁 矩阵翻转对称路径


for i in 0..n {
    for j in 0..i {
        let tmp = fruits[i][j];
        fruits[i][j] = fruits[j][i];
        fruits[j][i] = tmp;
    }
}


对于整数 a 和 b(b > 0),向上取整的公式为:

let ceil_div = (a + b - 1) / b;


核心:有多个任务,每个任务能做的时间有限,求最多能完成多少个。

🟢 贪心 + 排序 (Reverse 小顶堆)



本质:在不能重叠的区间中选择最多 k 个会议,使得 价值总和最大。

🟢 动态规划 with 二分差找优化

核心套路:
我们定义一个 DP 状态:
dp[i][j] 表示前 i 个会议中,最多选择 j 个会议所能获得的最大价值。

状态转移:
不选第 i 个会议:dp[i][j] = dp[i-1][j]
选第 i 个会议:
    找到第 i 个会议之前 最后一个不冲突的会议(结束时间 < 第 i 个会议的开始时间)
    然后转移:dp[i][j] = dp[prev][j-1] + value[i]

关键点:
    用 二分查找快速找到这个 prev。

📚 手写二分模板
// arr = [1, 3, 5, 6, 9]
// target = 6
// 应返回下标 2(arr[2] = 5 是最后一个 < 6 的)

// 查找右边界   
fn upper_bound_rightmost_less_than(arr: &[i32], target: i32) -> Option<usize> {
    if arr.is_empty() {
        return None;
    }
    let mut left = 0;
    let mut right = arr.len() - 1;

    while left < right {
        let mid = (left + right + 1) / 2;
        if arr[mid] < target {
            left = mid;
        } else {
            right = mid - 1;   // 向右靠拢
        }
    }

    if arr[left] < target {
        Some(left)
    } else {
        None
    }
}


// arr = [1, 3, 5, 6, 9]
// target = 5
// 应返回下标 2(arr[2] = 5 是第一个 >= 5 的)

// 差找左边界
fn lower_bound_first_ge(arr: &[i32], target: i32) -> Option<usize> {
    if arr.is_empty() {
        return None;
    }
    let mut left = 0;
    let mut right = arr.len(); // 注意这里是 arr.len()

    while left < right {
        let mid = (left + right) / 2;
        if arr[mid] < target {
            left = mid + 1;  // 向左靠拢.
        } else {
            right = mid;
        }
    }

    if left < arr.len() && arr[left] >= target {
        Some(left)
    } else {
        None
    }
}

// 返回的 left = 3, 6
fn lower_2(arr: &[i32], target: i32){
    let mut left = 0;
    let mut right = arr .len();
    while left < right {
        let mid = left + (right - left) / 2;
        // 最终
        // <= 是第一个大于 target 的idx
        // < 是第一个大于等于 target 的idx
        if arr[mid].0 <= target {  // 区别在这.
            left = mid + 1;
        } else {
            right = mid;
        }
    }
}




fn main() {
    let arr = [1, 3, 5, 6, 9];

    // 右边界查找
    if let Some(index) = upper_bound_rightmost_less_than(&arr, 6) {
        println!("最后一个 < 6 的下标是:{},值为 {}", index, arr[index]); // 输出 2, 值为 5
    } else {
        println!("没有小于 6 的元素");
    }

    // 左边界查找
    if let Some(index) = lower_bound_first_ge(&arr, 5) {
        println!("第一个 >= 5 的下标是:{},值为 {}", index, arr[index]); // 输出 2, 值为 5
    } else {
        println!("没有大于等于 5 的元素");
    }
}


// 标准二分查找(精确匹配)
// 在有序数组中查找恰好等于 target 的元素,如果存在返回下标,否则返回 -1。
fn binary_search_exact(arr: &[i32], target: i32) -> Option<usize> {
    let mut left = 0;
    let mut right = arr.len() - 1; // 闭区间 [left, right]

    while left <= right { // 注意是 <=,因为 right 是闭区间
        let mid = left + (right - left) / 2; // 防溢出写法
        if arr[mid] == target {
            return Some(mid); // 找到目标
        } else if arr[mid] < target {
            left = mid + 1;  // 目标在右侧,排除 mid
        } else {
            right = mid - 1; // 目标在左侧,排除 mid
        }
    }
    None // 未找到
}







others 随记


fn main() {
    let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
    
    // 找到第一个大于等于 5 的元素的位置
    let idx = nums.partition_point(|&x| x < 5);
    println!("{}", idx); // 输出 4(nums[4] = 5)
    
    // 找到第一个大于 5 的元素的位置
    let idx = nums.partition_point(|&x| x <= 5);
    println!("{}", idx); // 输出 5(nums[5] = 6)
}

Share this post on: