首页 > 其他分享 >三种二分查找写法(红蓝染色法理解)

三种二分查找写法(红蓝染色法理解)

时间:2025-01-20 22:30:18浏览次数:3  
标签:二分 right target int mid 染色法 区间 红蓝 left

二分查找使用前提:有序数组
用红蓝染色法理解二分查找数组中>=某个数的区间(闭区间写法)
定义红色区间表示<target的区间,蓝色区间表示>=target的区间,[left,right]区间是还未确定的区间
采用闭区间的写法,初始时闭区间范围为[0,n-1],即所有数都不确定,接着取中间下标mid,判断mid和target的大小关系,若mid比target小,那么说明mid左边所有数都比target小,因此mid及mid左边所有数都可标记为红色

如图target=8,第一次查找时mid=2,对应值为7<8,则说明mid左边所有数都小于target,标记为红色,改变未确定区间为[mid+1,right]

第二次查找mid=4,对应的值大于等于8,则右边所有值都可以确定大于等于8,标记为蓝色,未确定区间变为\[left,mid-1]

一直重复上述过程就可以将整个数组划分为红色和蓝色区间,而且可以知道每次循环结束后红色区间的结束位置为left-1,蓝色区间的开始位置为right+1,因此可以得到结论以闭区间的方式划分最后得到大于等于target的区间一定是在right+1的位置的。最后未确定的区间为空,要想让[left,right]为空,left=right+1,所以循环结束的条件就是left<=right,第一个>=target的位置就是left或者right+1

此外还需注意一些细节:
1. 若left和right都可能大于整形的范围的一半,所以会数值溢出,处理方法是写出mid = left +(right-left)/2的形式防止溢出
2. 若数组中的数都比target小,left最后会等于数组长度;除了这种情况外,数组里面可能还是没有等于target的值,因此最后找到的下标对应的值也不会等于target

闭区间写法:

int binarySearch(vector<int> v,int target){//查找大于等于的数的闭区间写法
        int left=0;
        int right=v.size();  //半开半闭区间[0,n)
        
        while(left<=right){  //闭区间[left,right],left可以等于right

            int mid = left +(right-left)/2;  //避免right+left溢出
            if(v[mid]<target){
                left=mid+1;     //区间变为[mid+1,right]
            }else{
                right=mid-1;    //[left,mid-1]
            }
        }
        return left;  //或者right+1    
    }

半开半闭和开区间的写法(以左闭右开为例)

  1. 若为左闭右开,开始时未确定的区间就是[0,n),也就是right开始时为n
  2. 比较完mid后left依然变成mid+1,但右边变成了开区间,所以right就变成mid就行
  3. 区间[left,right)最终为空条件为left=right,所以循环的条件就是left<right,最后left会等于right,并且第一个大于等于target的数就在right/left位置

int binarySearch(vector<int> v,int target){//查找大于等于的数的闭区间写法
        int left=0;
        int right=v.size();  //区间[0,n)
        
        while(left<right){  //区间[left,right)为空停止

            int mid = left +(right-left)/2;  //避免right+left溢出
            if(v[mid]<target){
                left=mid+1;     //区间变为[mid+1,right)
            }else{
                right=mid;    //[left,mid)
            }
        }
        
        return right;
    }

开区间

1. 初始时left=-1,right=n
2. 比较完mid后left=mid或者right=mid
3. 区间(left,right)最终为空条件为left+1=right,所以**循环的条件就是left+1\<right**,最后left+1=right,并且第一个大于等于target的数就在right位置

int binarySearch(vector<int> v,int target){//查找大于等于的数的闭区间写法
        int left=-1;
        int right=v.size();  //开区间(-1,n)
        
        while(left+1<right){  //开区间(left,right)为空停止

            int mid = left +(right-left)/2;  //避免right+left溢出
            if(v[mid]<target){
                left=mid;     //区间变为(mid,right)
            }else{
                right=mid;    //(left,mid)
            }
        }
        
        return right;     
}

其余情况:找 >、<=、< 的情况

- 大于x: 在整数的条件下相当于>=x+1
- 小于x: 看成>=x的第一个数左边的那个数
- 小于等于x: 转换成大于x(>=x+1)的左边的数


[34. 在排序数组中查找元素的第一个和最后一个位置](https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/)
[2529. 正整数和负整数的最大计数](https://leetcode.cn/problems/maximum-count-of-positive-integer-and-negative-integer/)
[2300. 咒语和药水的成功对数](https://leetcode.cn/problems/successful-pairs-of-spells-and-potions/) 1477 

[2187. 完成旅途的最少时间](https://leetcode.cn/problems/minimum-time-to-complete-trips/) 1641
[2563. 统计公平数对的数目](https://leetcode.cn/problems/count-the-number-of-fair-pairs/) 1721
[275. H 指数 II](https://leetcode.cn/problems/h-index-ii/)
[875. 爱吃香蕉的珂珂](https://leetcode.cn/problems/koko-eating-bananas/) 1766
[2861. 最大合金数](https://leetcode.cn/problems/maximum-number-of-alloys/) 1981
[2517. 礼盒的最大甜蜜度](https://leetcode.cn/problems/maximum-tastiness-of-candy-basket/) 2021
[2439. 最小化数组中的最大值](https://leetcode.cn/problems/minimize-maximum-of-array/) 1965

标签:二分,right,target,int,mid,染色法,区间,红蓝,left
From: https://blog.csdn.net/m0_74136087/article/details/145269140

相关文章

  • CDQ 分治 && 整体二分
    CDQ分治主要用于解决偏序问题。在偏序问题中,以三维偏序居多。它是一种离线算法。其实严格来说,它是一种思想而不是算法。它依赖于归并排序。CDQ分治也可以用于1D/1D动态规划的转移,不过目前暂不涉及。偏序问题什么是偏序?先从一维偏序说起。一维偏序给定\(n\)个点,每个点......
  • Atcoder ABC389E Square Price 题解 [ 绿 ] [ 二分 ] [ 贪心 ]
    SquarePrice:垃圾卡精度,垃圾卡精度,垃圾卡精度,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人,傻逼出题人。把ll改__int128前WA*22,改__int128直接AC了,难评。抛开卡精度这题还是挺好的。暴力先考虑暴力思路,显然暴力应该这么打:把所有物品全丢进优先队列......
  • 学习报告-论对“整体二分”的新理解
    学习报告-论对“整体二分”的新理解二分我们都知道,我们一般会通过二分具有单调性的答案来找到一个最接近某个点的答案。我们可能在以后的学习中遇到一些题,其答案是具有单调性的,但是如果让你在下面构造一个序列,或者构造一些答案,这些答案是无法二分的,只能“根据答案求过程”。然而......
  • 整体二分
    个人认为就是爆改cdq。大体思路和cdq相同:每次递归传入操作集合op和区间\([l,r]\),表示修改操作的修改位置以及查询操作的答案都位于\([l,r]\)内$;统计左区间修改对全区间查询的贡献;判断查询应下放到左右哪个区间;分割操作至左右两区间例题海亮OJ题单P3834【模板......
  • 二分
    1.解释其实这个东西吧,是分治的分支优点:时间复杂度低,十分简单,方便写,适用绝大多数题目缺点:总有人眼瞎写错()2.步骤1.在序列中确定中间数2.判断这数是不是,\(<\)的话去左边找,否则去右边找3.重复步骤直到中间数是要求的数字3.例题题目:洛谷P1873方法:朴素算法查找肯定超时,......
  • 二分查找算法的3种模板-PYTHON
    classbinary_search(object):def__init__(self,nums,target):self.nums=numsself.target=targetdefbinary_search_template_1(self):iflen(self.nums)==0:return-1l,r=0,len(self.nums)-1......
  • 搜索与图论(三)-最小生成树(Prim、Kruskal)和二分图(染色法、匈牙利法)
    目录一、最小生成树1.Prim算法 2.Kruskal算法二、二分图  1.判断二分图--染色体法 2.求二分图最大匹配--匈牙利算法一、最小生成树1.Prim算法         分为朴素Prim算法和堆优化Prim算法。写法和dijikstra算法类似,堆优化过程也类似,可类比学习。首......
  • day01 704. 二分查找&&27. 移除元素
    二分查找(search方法)publicintsearch(int[]nums,inttarget){intleft=0;intright=nums.length-1;intmid;while(left<=right){mid=(left+right)/2;if(nums[mid]==target){returnmid;}elseif(nums[mid]<target){left=mid+1;}else{right=mid-1;}}retur......
  • 【LeetCode 刷题】二分搜索
    此博客作为《代码随想录》的学习笔记,主要内容为二分搜索法及相关题目解析。文章目录704.二分查找35.搜索插入位置34.在排序数组中查找元素的第一个和最后一个位置69.x的平方根367.有效的完全平方数以下所有二分法算法均基于左闭右闭区间704.二分查找LeetCode......
  • 树状数组【单点修改+区间查询】+二分
    https://codeforces.com/gym/580226/problem/H#include<bits/stdc++.h>usingnamespacestd;#defineendl'\n'#definelowbit(x)x&(-x)usingll=longlong;usingpii=pair<int,int>;constdoublePI=acos(-1);constintN=2e5......