leetcode刷题总结之二分法模板

二分查找的前提:
查找的序列需要是有序的,若是无序的,则需要先给序列排序,然后再进行二分查找。

二分查找成功的三个步骤:

  • 1)预处理:如果序列未排序,则先进行排序
  • 2)二分查找:使用循环或递归将中间值元素与目标元素进行比较,将区间划分为两个子区间,然后再符合条件的其中一个子区间内进行寻找,直至循环或递归结束。
  • 3)后处理:在循环或递归完成后,需要对剩余区间的元素中确定符合条件的元素

模板1:寻找等于x的任意位置

//模板1:寻找等于x的任意位置
int search_1(vector<int>& nums, int x){
    if(nums.empty())return -1;
    int left=0,right=nums.size()-1;
    //循环结束的条件:区间内没有元素
    while(left<=right){
        int mid=left+((right-left)>>1);
        if(nums[mid]==x)return mid;//找到任意位置等于x,直接返回mid
        else if(nums[mid]>x)right=mid-1;//[mid,right]的所有元素都大于x,所以我们需要在小于等于x左边区间[left,mid-1]搜索x
        else left=mid+1;//[left,mid]的所有元素都小于x,所以我们需要在大于等于x的右边区间[mid+1,right]搜索x
    }
    return -1;
}

模板1的关键属性:

  • 1)模板1是二分查找最基本和最基础的形式
  • 2)查找元素可以不与元素两侧进行比较下确定,即向左查找为right=mid-1,向右查找为left=mid+1
  • 3)不需要进行后处理,因为在循环结束后,区间的元素数量为0

区别语法:

  • 1)二分区间为[0,size-1]
  • 2)向左查找right=mid-1;向右查找left=mid+1
  • 3)循环结束条件是:left>right即left=right+1

模板2:寻找大于等于x的最小值

//模板2:寻找大于等于x的最小值
int seach_2(vector<int>& nums,int x){
    int left=0,right=nums.size();
    //循环结束的条件:区间内只有一个元素
    while(left<right){
        int mid=left+((right-left)>>1);//向下取整,在left与right相差为1时,right可以取到left不会造成死循环
        if(nums[mid]>=x)right=mid;//mid之后的元素会比x更大,那么右边区间不满足条件,所以取right=mid(mid可能就是答案),也就是下一次搜索区间为[left,mid]
        else left=mid+1;//mid之前的元素包括mid都比x小,那么左半部分不满足条件,所以取left=mid+1(mid不满足条件),也就是下一次搜索区间为[mid+1,right]
    }
    //需判断找到的left是否满足条件
    if(left!=nums.size()&&nums[left]>=x)return left;
    return -1;
}

模板2的关键属性:

  • 1)寻找大于等于x的最小值
  • 2)查找的区间范围至少两个元素
  • 3)需要进行后处理,循环结束的条件是left=right即左右边界指向同一个元素,我们需要判断这个元素是否符合题目规定

区别语法:

  • 1)二分区间为[0,size)
  • 2)向左查找:right=mid,向右查找:left=mid+1
  • 3)循环结束的条件是:left=right

模板3:

//模板3:寻找小于等于x的最大值
int search_3(vector<int>& nums,int x){
    int left=0,right=nums.size();
    //循环结束的条件:区间内只有一个元素
    while(left<right){
        int mid=left+((right-left+1)>>1);//向上取整,在left与right相差为1时,left可以取到right而不会造成死循环
        if(nums[mid]<=x)left=mid;//mid之前的元素会比x更小,那么左边区间不满足条件,所以取left=mid(mid可能就是答案),也就是下一次搜索区间为[mid,right]
        else right=mid-1;//mid之后的元素包括mid都比x大,那么右边区间不满足条件,所以取right=mid-1(mid不满足条件),也就是下一次搜索区间为[left,mid-1]
    }
    //判断找到的left是否满足条件
    if(left!=nums.size()&&nums[left]<=x)return left;
    return -1;
}

模板3的关键属性:

  • 1)模板3是寻找小于等于x的最大值
  • 2)查找的区间中至少含有两个元素
  • 3)需要进行后处理,循环结束的条件是left==right,我们需要判断left或right指向的元素是否为目标值

区分语法:

  • 1)二分区间为[0,size-1)
  • 2)向左查找:right=mid-1,向右查找:left=mid
  • 3)循环结束的条件是:left==right

二分法的练习题:

题目 题解 难度
4. 寻找两个有序数组的中位数 C++ hard
33. 搜索旋转排序数组 C++ medium
34. 在排序数组中查找元素的第一个和最后一个位置 C++ medium
50. Pow(x, n) C++ mdium
69. x 的平方根 C++ easy
153. 寻找旋转排序数组中的最小值 C++ medium
154. 寻找旋转排序数组中的最小值 II C++ hard
162. 寻找峰值 C++ medium
278. 第一个错误的版本 C++ easy
287. 寻找重复数 C++ medium
209. 长度最小的子数组 C++ medium
349. 两个数组的交集 C++ easy
350. 两个数组的交集 II C++ easy
367. 有效的完全平方数 C++ easy
374. 猜数字大小 C++ easy
410. 分割数组的最大值 C++ hard
454. 四数相加 II C++ medium
658. 找到 K 个最接近的元素 C++ medium
704. 二分查找 C++ easy
719. 找出第 k 小的距离对 C++ hard

你可能感兴趣的:(数据结构)