Rust中的Vec如何进行二分查找

不吐不快:今天整整写了一天的论文,实在是有些头疼,写了半天也才堪堪写完第二章,这速度实在是感人。距离交稿也就不到十天了,还得加把劲。ε=(´ο`*)))唉,写完论文一定要好好玩几天!写累了,于是上力扣刷了一个1100左右的题,我本来想着用二分查找,查找最左边的值,自己不会写也就算了,没想到还不会调库。这令我十分汗颜,于是决定写下这个博客来记录一下,方便自己复习。

官方库

我们常见的二分查找有三种,以[1,2,2,2,2,3,3]为例,假设要查找2,那么可以查找它的左边,或者查找它的中间,或者查找它的右边,对应的下标分别为1,3,4。

在Rust的Vec类型里提供了binary_search方法,可以在有序数组中查找特定元素。

但是貌似并没有在Rust中实现查找左边和查找右边的算法?

这里先写一个最简单的例子:

Rust 复制代码
let a = vec![1,2,2,2,2,3,3];
let target = 5;
match a.binary_search(&target) {
    Ok(index) => println!("找到了,下标是{}", index),
    Err(_) => println!("梅找到"),
}

那么我们想实现左边和右边的算法,该如何用Rust实现呢? 我在Vec的方法中找到了一个partition_point的东东,请看:

Rust 复制代码
let nums = vec![1, 2, 3, 3, 4];
let target = 3;
let left = nums.partition_point(|&x| x < target);
println!("bisect_left: {}", left);

实际上它就可以实现bisect_left的功能,这个划分可以使当前所有左侧的元素都小于目标值。

同理,只需要将let left = nums.partition_point(|&x| x < target);中的<改成<=,那么就实际找到了右边的范围。

第三方库

实际上除了标准库之外,bisection这个外部库同样可以实现功能。

先在toml中写下依赖:

toml 复制代码
[dependencies]
bisection = "0.1" 具体版本是多少,可以用cargo search bisection

这个库中便可以实现我们之前提到的功能。

Rust 复制代码
use bisection::bisect_left;

let nums = vec![1, 2, 3, 3, 4];
let target = 3;
let left = bisect_left(&nums, &target);
println!("bisect_left: {}", left); // 输出:2

let right = bisect_right(&nums, &target);
println!("bisect_right: {}", right); // 输出:4

手动实现

明天写吧,今天太晚了。

我才不会告诉你我又写出bug了....


更新时间:2025年04月13日09:55:42

OK兄弟们我又来了,新鲜的代码出炉:

Rust 复制代码
fn bisect_left(nums: &Vec<i32>, target: i32) -> i32 {
    let (mut left, mut right) = (0, nums.len() as i32 - 1);

    while left <= right {
        let mid = left + (right - left) / 2;
        if nums[mid as usize] < target {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    if left > nums.len() as i32 {
        nums.len() as i32
    } else {
        left
    }
}

fn bisect_right(nums: &Vec<i32>, target: i32) -> i32 {
    let (mut left, mut right) = (0, nums.len() as i32 - 1);

    while left <= right {
        let mid = left + (right - left) / 2;
        if nums[mid as usize] <= target {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    left
}

fn main() {
    let nums = vec![3, 3, 4];
    
    println!("{}", bisect_left(&nums, 3)); // 输出 0
    println!("{}", bisect_right(&nums, 3)); // 输出 2
}

原汁原味的Rust,但是我实际上这里还有一些边界问题没有处理干净,其他一些逻辑也有些许复杂,不过核心思想就是,bisect_left强调<,bisect_right强调<=,其实和我们之前提到的partition_point是基本一样的,好了,至此大功告成,一个简单的问题,被我这么复杂的写了出来!

相关推荐
星释1 小时前
Rust 练习册 :Pig Latin与语言游戏
游戏·rust·c#
2301_795167201 小时前
玩转Rust高级应用 如何让让运算符支持自定义类型,通过运算符重载的方式是针对自定义类型吗?
开发语言·后端·算法·安全·rust
ftpeak3 小时前
《Rust+Slint:跨平台GUI应用》第八章 窗体
开发语言·ui·rust·slint
百锦再6 小时前
第10章 错误处理
java·git·ai·rust·go·错误·pathon
2301_795167208 小时前
玩转Rust高级应用. ToOwned trait 提供的是一种更“泛化”的Clone 的功能,Clone一般是从&T类型变量创造一个新的T类型变量
开发语言·后端·rust
星释8 小时前
Rust 练习册 :Phone Number与电话号码处理
开发语言·机器学习·rust
2301_796512529 小时前
Rust编程学习 - 问号运算符会return一个Result 类型,但是如何使用main函数中使用问号运算符
开发语言·学习·算法·rust
星释9 小时前
Rust 练习册 :Poker与扑克牌游戏
开发语言·游戏·rust
2301_7951672014 小时前
玩转Rust高级应用 如何避免对空指针做“解引用”操作,在C/C++ 里面就是未定义行为
c语言·c++·rust
星释14 小时前
Rust 练习册 :Leap与日期计算
开发语言·后端·rust