
LeetCode 34 在排序数组中查找元素的第一个和最后一个位置的 Rust 实现核心思路是两次二分查找分别寻找目标元素的左边界和右边界。算法思路这道题考察的是二分查找的边界收缩寻找左边界当 nums[mid] target 时不立即返回而是收缩右边界right mid - 1继续向左半部分寻找。寻找右边界当 nums[mid] target 时收缩左边界left mid 1继续向右半部分寻找。注意由于我们在命中目标时继续收缩边界最终 left 和 right 会越界或指向非目标元素。因此最后需要判断 left 是否合法且对应元素是否真的等于 target。Rust 代码实现impl Solution {pub fn search_range(nums: Vec, target: i32) - Vec {// 寻找左边界let mut left: usize 0;let mut right: usize nums.len(); // 注意右边界初始化为 len而非 len - 1while left right { let mid left (right - left) / 2; if nums[mid] target { left mid 1; } else { // 当 nums[mid] target 时收缩右边界 right mid; } } // 循环结束时left 指向第一个等于 target 的位置 let left_idx left; // 寻找右边界 left 0; right nums.len(); while left right { let mid left (right - left) / 2; if nums[mid] target { // 当 nums[mid] target 时收缩左边界 left mid 1; } else { right mid; } } // 循环结束时left - 1 指向最后一个等于 target 的位置 let right_idx left - 1; // 边界检查如果 left_idx 越界或者对应元素不等于 target说明数组中不存在 target if left_idx nums.len() nums[left_idx] target { return vec![left_idx as i32, right_idx as i32]; } vec![-1, -1] }}Rust 实现的关键细节防止 usize 溢出在 Rust 中数组下标类型是 usize无符号整数。如果直接写 (left right) / 2当 left 和 right 都非常大时left right 可能会触发整数溢出Debug 模式下会直接 panic。因此必须使用 left (right - left) / 2 来安全地计算中点。搜索区间 [left, right)与 Python 版本中使用的闭区间 [left, right] 不同Rust 代码中使用了左闭右开区间 [left, right)。初始时 right nums.len()。循环条件为 left right。这种写法在 Rust 中非常常见因为它可以完美避免 nums.len() 0 时 nums.len() - 1 导致的 usize 下溢Underflow问题。类型转换函数的返回值是 Vec而 Rust 中的数组下标是 usize。在返回结果时需要使用 as i32 进行显式类型转换。为什么最后检查 left_idx 而不是 right_idx因为 left_idx 是第一个 target 的位置。如果 target 不存在比如找 9left_idx 可能会停在 10 的位置或者越界。只要 left_idx 合法且 nums[left_idx] target就一定能推导出 right_idx 也是合法的。掌握这种“遇到目标值不返回而是继续收缩边界”的二分思想可以秒杀所有求边界的二分题如 LeetCode 278 第一个错误的版本、LeetCode 35 搜索插入位置等。需要我帮你把这道题的合并写法单函数实现通过传入布尔值决定收缩哪一边也写出来吗面试时写单函数会显得更精炼。