AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

二分查找Binary Search三种形式, 二维二分

作者: 作者的头像   迷弟 ,  2025-07-04 22:22:14 · 广东 ,  所有人可见 ,  阅读 4


0


准确值,左边界,右边界。

  1. 精准值
int search(vector<int>& a, int t) {
    int l = 0, r = a.size() - 1;
    while (l <= r){
        int mid = l + (r-l)/2;
        if (a[mid] == t) return mid; //
        else if (a[mid] < t) l = mid + 1;
        else r = mid -1;
    }
    return -1;
}
  1. 从左边查左边界. >=target
int l = 0, r = a.size() ;
while (l < r){
    int mid = l + (r-l)/2;
    if (a[mid] < t) l = mid + 1;
    else r = mid;
}
return l;
  1. 从右边查右边界. <=target
int l = 0, r = a.size() ;
while (l < r){
    int mid = l + (r-l)/2;
    if (a[mid] <= t) l = mid + 1; //因为有等于,所以l最后一下会越过去.l-1即为右界
    else r = mid;
}
return l - 1;//注意些边界,精准查时特判a[mid]==t return mid;

例题:789. 数的范围
给定一个按照升序排列的长度为 n的整数数组,以及 q个查询。
对于每个查询,返回一个元素 k的起始位置和终止位置(位置从 0开始计数)。如果没有返回-1 -1

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
//binary search of k, left and right range 区间's index
PII solve(vector<int> a, int k){
    int l = 0, r = a.size();
    while (l < r){
        int mid = l + (r - l) / 2;
        if (a[mid] < k) l = mid + 1;
        else r = mid;
    }
    int left = l;

    int l2 = 0, r2 = a.size();
    while (l2 < r2){
        int mid = l2 + (r2 - l2)/2;
        if (a[mid] <= k) l2 = mid + 1;
        else r2 = mid;
    }
    int right = l2 - 1;
    if (left >= a.size()||a[left]!=k) return {-1,-1};
    return {left,right};
}
int main(){
    int n, q;
    cin >> n >> q;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < q; i ++ ){
        int k;
        cin >> k;
        auto result = solve(a,k);
        cout << result.first << " " << result.second << '\n';
    }
    return 0;
}

二维二分。

简单起见就不用双二分了,循环+每行二分。

bool Find(int target, vector<vector<int>>& a) {
    if (a.empty() || a[0].empty()) return false;
    int m = a.size(), n = a[0].size();
    for (int i = 0; i < m;i++){
        int l = 0, r = n;
        while(l < r){
            int mid = l + (r - l)/2;
            if (a[i][mid] == target){ return true; break;}
            if (a[i][mid] < target){ l = mid + 1;}
            else{r = mid;}
        }
    }
    return false;
}

旋转数组:
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。请问,给定这样一个旋转数组,求数组中的最小值。

输入:
[3,4,5,1,2]
返回值:
1
int minNumberInRotateArray(vector<int>& nums) {
        // write code here
        int carry = -1;
        for (int i = 0; i < nums.size();i++){
            if (nums[i] < carry){
                return nums[i];
                break;
            }
            carry = nums[i];
        }
        return nums[0]; //太坑了 竟然给不旋转的混进来 [1,2,2,2,2,2]
    }

山峰O(n)遍历

int findPeakElement(vector<int>& nums) {
    // write code here
    if (nums.size()<=1) return 0;
    int carry = INT_MIN;
    for (int i = 0; i < nums.size();i++){
        if (nums[i] < carry){
            return i-1;
            break;
        }
        //cout << carry << ' ' << "i是" << i <<'\n';
        carry = nums[i];
    }
    return nums.size()-1; //一路递增的山峰
}

二分O(log_2 n) (其中一个山峰即可)

int findPeakElement(vector<int>& a) {
    if (a.size()<=1) return 0;
    int l = 0, r = a.size()-1;
    while (l < r){
        int mid = l + (r - l)/2;
        if (a[mid] < a[mid + 1]) l = mid + 1;
        else r = mid;
    }
    return l;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息