704.二分查找
题目:二分查找
讲解视频:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html
讲解文章:https://www.bilibili.com/video/BV1fA4y1o715
尝试
int search(vector<int>& nums, int target) {
int len;
//consider n = 1
len = nums.size();
if(len == 1){
if(target == nums[0])
return 0;
else
return -1;
}
//while n > 1,set init state
int left,right,mid;
left = 0;
right = len-1;
mid = (left + right )/2;
while(right-left > 1 ){
if(target == nums[mid]){
return mid;
}
else if(target < nums[mid]){
right = mid;
}
else if(target > nums[mid]){
left = mid;
}
mid = (left + right )/2;
}
if(target == nums[left]){
return left;
}
else if(target == nums[right]){
return right;
}
else
return -1;
}
思路
头、尾、中间 三个坐标的变换。
- 将目标值与数组中间下标值比较,
- 找到则返回下标
- 否则,在前半或后半数组中继续。
实现
问题
- 把下标当作数字看待,因为整数下取整的问题,当头、尾下标差为1时,头、尾、中间 三个坐标的变换出现循环。
len
作为中间变量,冗余
解决
- 条件分支,分类讨论。繁琐。
题解理解
class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (right - left) / 2 + left;
int num = nums[mid];
if (num == target) {
return mid;
} else if (num > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
}
思路
把下标与数组的整数具象化为指针和存储空间,再来考虑指针的变换。
讲解
讲解重点
代搜索区间是算法的循环不变量。区间可以分类为左闭右闭,左闭右开,左开右闭等情况。常规考虑:
- 左闭右闭
- while 的条件 :left<=right
- middle的赋值 : right = middle-1 (middle不在区间内)
- 左开右闭
- 初始值 :right = nums.length
- while 的条件 :left<right
- middle的赋值 : right = middle (middle不在区间内,right包含不在区间内的值)
27.移除元素
暴力求解
从头开始,
- 遇到val,就将剩余元素均前移一位,长度减一;
- 遇到非val,比较位向后一位。
双指针
同向
- 指针的作用
- 快指针:找新数组最新需要的值
- 满指针:找新数组最新可用下标
- 元素相对位置不变,但是同方向若val在开头,剩余都要向左移动,数组元素移动次数较多。
双向
- 指针的作用
- 左指针从0开始,右指针从数组最后一位开始
- 左指针要移除,就将右指针所指数覆盖到左指针处
*当val在数组中出现次数较少时,优化效果明显。
收获
- 找准循环不变量
- 二分搜索:以区间作为整体进行思考,保证边界条件的一致性。
- 双指针操作
- 移除元素:一个指针指向值,一个指向下标