题目链接:leetcode704-二分查找, leetcode27-移除元素
二分
注意事项:开闭区间
如果右闭,则right=len(nums)-1, for left <= right {}, right=mid-1
如果右开,则right=len(nums), for left < right {}, right=mid
Go
左开右闭合: [left, right]
func search(nums []int, target int) int {left, right := 0, len(nums)-1mid := 0for left <= right {mid = ((right - left) >> 1) + leftif nums[mid] < target {// 说明target在mid右边,mid向右边移动left = mid + 1} else if nums[mid] > target {// 说明target在mid左边,mid向左边移动right = mid - 1} else {return mid}}return -1
}
左闭右开:[left, right)
func search(nums []int, target int) int {left, right := 0, len(nums)mid := 0for left < right {mid = ((right - left) >> 1) + leftif nums[mid] < target {// 说明target在mid右边, mid右边移动left = mid + 1} else if nums[mid] > target {// 说明target在mid左边,mid左边移动right = mid} else {return mid}}return -1
}
Rust
左开右闭合: [left, right]
之所以使用i32是因为当mid为0时, mid-1会报错(Vector的索引是usize类型)
pub fn search(nums: Vec<i32>, target: i32) -> i32 {let (mut left, mut right, mut mid) = (0, (nums.len() - 1) as i32, 0);while left <= right {mid = ((right - left) >> 1) + left;if nums[mid as usize] < target {// 说明target在右区间left = mid+1;} else if nums[mid as usize] > target {// 说明target在左边区间right = mid -1 ;} else {return mid as i32;}}return -1;}
左闭右开:[left, right)
pub fn search(nums: Vec<i32>, target: i32) -> i32 {let (mut left, mut right, mut mid) = (0usize, nums.len() - 1, 0usize);while left < right {mid = ((right - left) >> 1) + left;if nums[mid] < target {// 说明target在右区间left = mid+1;} else if nums[mid] > target {// 说明target在左边区间right = mid;} else {return mid as i32;}}return -1;}
移除元素
数组的长度是固定的,无法进行删除,所谓的元素删除也只是将目标val移动到数组的末尾作为无效的值,同时对数组中有效值的数量进行标识,如数组所允许访问的索引范围为[0, 有效值的数量)。
Go
双指针法,不再关系无效的val,让有效的val从索引为0开始重组数组(无效的值会被覆盖,不再关心)
如果不想无效的val被覆盖,可以参考相向双指针法,将无效的val全都移动到数组的尾部
func removeElement(nums []int, val int) int {idx, numLen := 0, len(nums)for fast := 0; fast < numLen; fast++ {if nums[fast] == val {continue}nums[idx] = nums[fast]idx++}return idx
}
相向双指针法,将无效的val全都移动到数组的尾部, 但是数组中的值的顺序会发生变化
基本思路:
- 存在双指针:left, right,left从索引为0的位置向数组尾部移动,right从索引为len(nums)-1的位置开始向数组头部移动
- 让left发现指定的val,停止不动,当right发现非指定的val,停止不动
- 交换left和right所指向的值
- 重复2,3过程,直到left > right跳出循环
func removeElement(nums []int, val int) int {left, right := 0, len(nums)-1for left <= right {// left指向val的位置for left <= right && nums[left] != val {left++}// right指向非val的位置for left <= right && nums[right] == val {right--}// 如果移动之后依旧满足left < right, 则交换left和right所指向的值if left > right {break}nums[left], nums[right] = nums[right], nums[left]left++right--}return left
}
Rust
双指针法
pub fn remove_element(nums: &mut Vec<i32>, val: i32) -> i32 {let mut slow = 0usize;for fast in (0..nums.len()) {if nums[fast] == val {continue}nums[slow] = nums[fast];slow += 1;}slow as i32}
相向双指针
pub fn remove_element(nums: &mut Vec<i32>, val: i32) -> i32 {let (mut left, mut right) = (0 , nums.len() as i32 - 1);while left <= right {// left指向val的位置while left <= right && nums[left as usize] != val {left += 1;}// right指向非val的位置while left <= right && nums[right as usize] == val {// 使用uize,这里可能会报错right -= 1;}if left > right {break}// 交换值(nums[left as usize], nums[right as usize]) = (nums[right as usize], nums[left as usize]);left += 1;right -= 1;}left}