二分查找的习题集

文章摘要:文章收集各个网站包括力扣,洛谷二分查找习题。同时给出我的Python、C++代码,但是代码不作过多解释。

文章目录

  • 力扣
    • 278. 第一个错误的版本。
    • 35. 搜索插入位置
    • 74. 搜索二维矩阵
    • 240. 搜索二维矩阵 II
    • 162. 寻找峰值
    • 33. 搜索旋转排序数组
    • 81. 搜索旋转排序数组 II
    • 153. 寻找旋转排序数组中的最小值
    • 154. 寻找旋转排序数组中的最小值 II
  • 洛谷
    • P2249 【深基13.例1】查找
  • 后记

力扣

278. 第一个错误的版本。

超链。PS1:这是最最简单的二分查找了。就是调用了一个api注意一下。PS2:还有一点需要注意就是:对于C++尽量去使用 r + ( r − l ) / 2 r+(r-l)/2 r+(rl)/2而不是 ( r + l ) / 2 (r+l)/2 (r+l)/2,虽然两者在数学上是等效的但是后者可能造成数值溢出(显而易见;事实上这道题C++使用后一种就过不了)。数值溢出应该是有解决方法,但是我不知道所以后种公式。
Python

# The isBadVersion API is already defined for you.
# def isBadVersion(version: int) -> bool:

class Solution:
    def firstBadVersion(self, n: int) -> int:
        if isBadVersion(1)==1:
            return 1
        l,r=1,n
        while l+1!=r:
            m=(l+r)//2
            if isBadVersion(m)==0:
                l=m
            else:
                r=m
        return r

C++

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        if(isBadVersion(1)==1){return 1;}
        int l=1,r=n;
        while(l+1!=r){
            int m=l+(r-l)/2;
            if(isBadVersion(m)==0){l=m;}
            else{r=m;}
        }
        return r;
    }
};

35. 搜索插入位置

超链。PS:也很简单。注意一下返回即可。
Python

class Solution:
    def searchInsert(self,nums:List[int],target:int)->int:
        if target<nums[0]:
            return 0
        if target>nums[-1]:
            return len(nums)
        l,r=0,len(nums)
        while l<=r:
            m=(l+r)//2
            if target<nums[m]:
                r=m-1
            elif target>nums[m]:
                l=m+1
            else:
                return m
        return r+1

C++

class Solution{
public:
    int searchInsert(vector<int>&nums,int target){
        //C++中不能使用负数进行索引
        int n=nums.size();
        int l=0,r=n-1;
        if(target<nums[0]){return 0;}
        if(target>nums[n-1]){return n;}
        while(l<=r){
            int m=(l+r)/2;
            if(target>nums[m]){l=m+1;}
            else if(target<nums[m]){r=m-1;}
            else{return m;}
        }
        return r+1;
    }
};

74. 搜索二维矩阵

超链。PS:也很简单。纵着来一次,横着来一次。
Python

class Solution:
    def searchMatrix(self,matrix:List[List[int]],target:int)->bool:
        if target<matrix[0][0]:
            return False
        if target>matrix[-1][-1]:
            return False
        lt=[]
        for i in matrix:
            for j in i:
                lt.append(j)
        l,r=0,len(lt)-1
        while l<=r:
            m=(l+r)//2
            if target>lt[m]:
                l=m+1
            elif target<lt[m]:
                r=m-1
            else:
                return True
        return False

C++

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n=matrix.size(),m=matrix[0].size();
        if(target<matrix[0][0]){return 0;}
        if(target>matrix[n-1][m-1]){return 0;}
        int l1=0,r1=n-1;
        while(l1<=r1){
            int m1=(l1+r1)/2;
            if(target>matrix[m1][0]){l1=m1+1;}
            else if(target<matrix[m1][0]){r1=m1-1;}
            else{return 1;}
        }
        int l2=0,r2=m-1;
        while(l2<=r2){
            int m2=(l2+r2)/2;
            if(target>matrix[r1][m2]){l2=m2+1;}
            else if(target<matrix[r1][m2]){r2=m2-1;}
            else{return 1;}
        }
        return 0;
    }
};

240. 搜索二维矩阵 II

超链。也很简单。每行都给它来一次。
Python

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if target<matrix[0][0]:
            return 0
        if target>matrix[-1][-1]:
            return 0
        for i in matrix:
            l,r=0,len(i)-1
            while l<=r:
                m=(l+r)//2
                if target>i[m]:
                    l=m+1
                elif target<i[m]:
                    r=m-1
                else:
                    return 1
        return 0

C++

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int n=matrix.size(),m=matrix[0].size();
        if(target<matrix[0][0]){return 0;}
        if(target>matrix[n-1][m-1]){return 0;}
        for(int i=0;i<n;i++){
            int l=0,r=m-1;
            while(l<=r){
                int m=(r+l)/2;
                if(target>matrix[i][m]){l=m+1;}
                else if(target<matrix[i][m]){r=m-1;}
                else{return 1;};
            }
        }
        return 0;
    }
};

162. 寻找峰值

超链。PS:这里我们始终保证 n u m s [ l ] > n u m s [ l − 1 ] , n u m s [ r ] > n u m s [ r + 1 ] nums[l]>nums[l-1],nums[r]>nums[r+1] nums[l]>nums[l1],nums[r]>nums[r+1]。当 r = l r=l r=l时有 n u m s [ l − 1 ] < n u m s [ l ] = n u m s [ r ] < n u m s [ r + 1 ] nums[l-1]nums[l1]<nums[l]=nums[r]<nums[r+1]。所以 r    o r    l r\;or\;l rorl为峰值。注意边界条件 / / /初始条件成立(题目说了)。
Python

class Solution:
    def findPeakElement(self, nums: List[int]) -> int:
        l,r=0,len(nums)-1
        while l!=r:
            m1=(l+r)//2;m2=(l+r)//2+1
            if nums[m1]<nums[m2]:
                l=m2
            else:
                r=m1
        return r

C++

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int l=0,r=nums.size()-1;
        while(l!=r){
            int m1=(l+r)/2,m2=(l+r)/2+1;
            if(nums[m1]<nums[m2]){l=m2;}
            if(nums[m1]>nums[m2]){r=m1;}
        }
        return l;
    }
};

33. 搜索旋转排序数组

超链。PS1:也很简单。先把旋转的点找到,然后再来找目标值,两次二分法就好了。PS2:注意一下特殊条件以及边界情况即可。
Python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if len(nums)==1:
            if nums[0]==target:
                return 0
            return -1
        if nums[0]<nums[-1]:
            l,r=0,len(nums)-1
        else:
            l_new,r_new=0,len(nums)-1
            while l_new+1!=r_new:
                m_new=(l_new+r_new)//2
                if nums[m_new]>nums[l_new]:
                    l_new=m_new
                if nums[m_new]<nums[r_new]:
                    r_new=m_new
            if target>=nums[0]:
                l,r=0,l_new
            else:
                l,r=r_new,len(nums)-1
        if target<nums[l] or target>nums[r]:
            return -1
        while l<=r:
            m=(l+r)//2
            if nums[m]>target:
                r=m-1
            elif nums[m]<target:
                l=m+1
            else:
                return m
        return -1

C++

class Solution {
public:
    int search(vector<int>& nums, int target) {
        if(nums.size()==1){
            if(nums[0]==target){return 0;}
            return -1;
        }
        int r,l;
        if(nums[0]<nums[nums.size()-1]){
            l=0,r=nums.size()-1;
        }
        else{
            int l_new=0,r_new=nums.size()-1;
            while(l_new+1!=r_new){
                int m_new=l_new+(r_new-l_new)/2;
                if(nums[m_new]>nums[l_new]){l_new=m_new;}
                if(nums[m_new]<nums[r_new]){r_new=m_new;}
            }
            if(target>=nums[0]){l=0,r=l_new;}
            else{l=r_new,r=nums.size()-1;}
        }
        if(target<nums[l]||target>nums[r]){return -1;}
        while(l<=r){
            int m=l+(r-l)/2;
            if(nums[m]>target){r=m-1;}
            else if(nums[m]<target){l=m+1;}
            else{return m;}
        }
        return -1;
    }
};

81. 搜索旋转排序数组 II

超链:。PS:思路同上,略有改动。
Python

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if len(nums)==1:
            if nums[0]==target:
                return True
            return False
        l,r=0,len(nums)-1
        while True:
            cnt=0
            if nums[l]==nums[l+1] and l+1!=r:
                l+=1;cnt+=1
            if nums[r]==nums[r-1] and r-1!=l:
                r-=1;cnt+=1
            if cnt==0:
                break
        if l+1==r:
            if nums[l]==target or nums[r]==target:
                return True
            else:
                return False
        else:
            if nums[l+1]>nums[r] or nums[r-1]<nums[l]:
                a,b=l,r
                while l+1!=r:
                    m=l+(r-l)//2
                    if nums[m]>=nums[l]:
                        l=m
                    if nums[m]<=nums[r]:
                        r=m
                if target>=nums[a]:
                    l,r=a,l
                else:
                    l,r=r,b
        if target<nums[l] or target>nums[r]:
            return False
        while l<=r:
            m=l+(r-l)//2
            if nums[m]>target:
                r=m-1
            elif nums[m]<target:
                l=m+1
            else:
                return True
        return False

C++

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        if(nums.size()==1){
            if(nums[0]==target){return true;}
            else{return false;}
        }
        int l=0,r=nums.size()-1;
        while(1){
            int cnt=0;
            if(nums[l]==nums[l+1]&&l+1!=r){l+=1;cnt+=1;}
            if(nums[r]==nums[r-1]&&r-1!=l){r-=1;cnt+=1;}
            if(cnt==0){break;}
        }
        if(l+1==r){
            if(nums[l]==target||nums[r]==target){return true;}
            else{return false;}
        }
        else{
            if(nums[l+1]>=nums[r]||nums[r-1]<=nums[l]){
                int a=l,b=r;
                while(l+1!=r){
                    int m=l+(r-l)/2;
                    if(nums[m]>=nums[l]){l=m;}
                    if(nums[m]<=nums[r]){r=m;}
                }
                if(target>=nums[a]){r=l;l=a;}
                else{l=r;r=b;}
            }
        }
        if(target<nums[l]||target>nums[r]){return false;}
        while(l<=r){
            int m=l+(r-l)/2;
            if(nums[m]>target){r=m-1;}
            else if(nums[m]<target){l=m+1;}
            else{return true;}
        }
        return false;
    }
};

153. 寻找旋转排序数组中的最小值

超链。PS:会上面两道题,这道题就简单。这道题只包含上面的第一步。
Python

class Solution:
    def findMin(self, nums: List[int]) -> int:
        if len(nums)==1:
            return nums[0]
        if nums[0]<nums[-1]:
            return nums[0]
        l,r=0,len(nums)-1
        while l+1!=r:
            m=l+(r-l)//2
            if nums[m]>nums[l]:
                l=m
            if nums[m]<nums[r]:
                r=m
        return nums[r]

C++

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums.size()==1){return nums[0];}
        if(nums[0]<nums[nums.size()-1]){return nums[0];}
        int l=0,r=nums.size()-1;
        while(l+1!=r){
            int m=l+(r-l)/2;
            if(nums[m]>nums[l]){l=m;}
            if(nums[m]<nums[r]){r=m;}
        }
        return nums[r];
    }
};

154. 寻找旋转排序数组中的最小值 II

超链。PS:思路同上,略有改动。
Python

class Solution:
    def findMin(self, nums: List[int]) -> int:
        if len(nums)==1:
            return nums[0]
        l,r=0,len(nums)-1
        while True:
            cnt=0
            if nums[l]==nums[l+1] and l+1!=r:
                l+=1;cnt+=1
            if nums[r]==nums[r-1] and r-1!=l:
                r-=1;cnt+=1
            if cnt==0:
                break
        if l+1==r:
            return min(nums[l],nums[r])
        else:
            if nums[l+1]>nums[r] or nums[r-1]<nums[l]:
                while l+1!=r:
                    m=l+(r-l)//2
                    if nums[m]>=nums[l]:
                        l=m
                    if nums[m]<=nums[r]:
                        r=m
                return nums[r]
            else:
                return nums[0]

C++

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums.size()==1){return nums[0];}
        int l=0,r=nums.size()-1;
        while(1){
            int cnt=0;
            if(nums[l]==nums[l+1]&&l+1!=r){l+=1;cnt+=1;}
            if(nums[r]==nums[r-1]&&r-1!=l){r-=1;cnt+=1;}
            if(cnt==0){break;}
        }
        if(l+1==r){
            if(nums[l]<nums[r]){return nums[l];}
            else{return nums[r];}
        }
        else{
            if(nums[l+1]>nums[r]||nums[r-1]<nums[l]){
                while(l+1!=r){
                    int m=l+(r-l)/2;
                    if(nums[m]>=nums[l]){l=m;}
                    if(nums[m]<=nums[r]){r=m;}
                }
                return nums[r];
            }
            else{return nums[0];}
        }
    }
};

洛谷

PS:鉴于博主没有系统学习过C++只有一点点C基础所以输入输出我是完全不懂所以洛谷就只给Python代码了吧。之后也不打算进行补充毕竟语言只是一种工具。

P2249 【深基13.例1】查找

超链。PS:最简单的思路便是对于每个查询进行二分查找。但是还是感觉有点浪费时间,所以我们这样来做。首先对于查询列表进行排序以及删除重复元素。每次查询,左界选择上一次的索引右边一个就好。
Python

def function1(l,r,x,lt):
    while l<=r:
        m=l+(r-l)//2
        if lt[m]>x:
            r=m-1
        elif lt[m]<x:
            l=m+1
        else:
            return m
    return -1
def function2(x,lt):
    while True:
        if x>=1 and lt[x]==lt[x-1]:
            x-=1
        else:
            return x
n,m=map(int,input().strip().split())
lt1=[int(i) for i in input().strip().split()]
lt2=[int(i) for i in input().strip().split()]
lt3=list(set(lt2));lt3.sort();zd={};l=0
for i in lt3:
    x=function1(l,n-1,i,lt1)
    if x!=-1:
        l=x+1
    if x==-1:
        zd[i]=-1
    else:
        zd[i]=function2(x,lt1)+1
for i in lt2:
    print(zd[i],end=" ")

后记

感觉到这基本练得差不多了。数值分析也有很多二分查找思想案例,数值分析我也想好好搞;洛谷官方题单也有二分查找经典题单,洛谷官方题单希望做完。这篇文章就到这了,其他二分查找案例见以后的更新博文。希望下次能够熟练掌握C++吧。

你可能感兴趣的:(算法习题,算法,力扣,洛谷)