0
点赞
收藏
分享

微信扫一扫

二分查找(模板和应用)

悄然丝语 2022-03-11 阅读 59

二分查找(模板和应用)

二分查找的定义和用途,笔者觉得无需再多说什么,这里直接给出二分查找的两个模板,和一个简单例题,以供大家查阅和参考。

首先,二分查找是针对有序的单调不增或单调不减数组的,这应该没有问题,那么,在使用二分法的时候,记得先用 s o r t sort sort 函数对数组进行排序!

1.返回数组中待查找元素首次出现的位置

#include <iostream>
#include <algorithm>

using namespace std;

int a[15] = {0, 1, 4, 3, 3, 2, 4, 5, 7, 8, 4};  // 数组从1 开始计数,对“1, 4, 3, 3, 2, 4, 5, 7, 8, 4”这个区间使用二分查找制定元素首次出现的序号
int n = 10;  // 数组的大小

// 二分
int find(int x)
{
	int L = 1, r = n + 1; // 针对一个 [1,n+1) 的左开右闭区间
    while (L < r)
    {
        int mid = L + (r - L) / 2; // 这样做是为了防止爆 int
        if (a[mid] >= x)
            r = mid; // 抛弃右边的所有数字,但不抛弃 a[mid]
        else
            L = mid + 1; // 抛弃左边所有数字 和 a[mid]
    }
    if (a[L] == x)
        return L; // 此时返回的就是 x 在数组中第一个出现的位置
    else
        return -1;
}

int main()
{
	sort(a+1,a+1+n);
	int first = find(3); // 找3第一次出现的位置
	cout << first;
	return 0;
}

如果看不懂边界条件,先记住就行了!因为我也看不太懂
运行结果:
输出:3

2.返回数组中待查找元素最后一次出现的位置

#include <iostream>
#include <algorithm>

using namespace std;

int a[15] = {0, 1, 4, 3, 3, 2, 4, 5, 7, 8, 4};  // 数组从1 开始计数,对“1, 4, 3, 3, 2, 4, 5, 7, 8, 4”这个区间使用二分查找制定元素首次出现的序号
int n = 10;  // 数组的大小
int find(int x)
{
    int l = 1, r = n + 1;
    while (l < r)
    {
        int mid = l + (r - l) / 2;
        if (a[mid] <= x)
            l = mid + 1;
        else
            r = mid;
    }  //while 运行结束后,l对应的是“最后一次出现的位置+1”,因此后续要减一
    if (a[l - 1] == x) 
        return l - 1;
    else
        return -1;
}
int main()
{
 
    sort(a + 1, a + 1 + n);
    int ans = find(3);
    cout << ans;
    return 0;
}

运行结果:4

例题

洛谷P1102
题目分析:
转化为列举 A = B+ C,同时枚举B即可

#include <iostream>
#include <algorithm>

using namespace std;

#define ll long long
const int MA = 2e5 + 10;

ll a[MA], tol;
int n, c;

int main()
{
    scanf("%d%d", &n, &c);
    for (int i = 0; i < n; i++)
        scanf("%lld", &a[i]);
    sort(a, a + n);
    ll tol = 0;
    for (int i = 0; i < n; i++) // 枚举 B
    {
        int x = a[i] + c;  // x 的值 对应的 就是 A 的值,枚举的a[i] 就是 B
        // 二分找此时的 x (A) 第一次出现的位置
        int l = i, r = n;
        while (l < r)
        {
            int mid = l + (r - l) / 2;
            if (a[mid] >= x)
                r = mid;
            else
                l = mid + 1;
        }
        if (a[l] == x)  // 找到了
        {
        	// 接下来二分找 x(A) 最后一次出现的位置
            int l2 = l, r2 = n;
            while (l2 < r2)
            {
                int mid2 = l2 + (r2 - l2) / 2;
                if (a[mid2] <= x)
                    l2 = mid2 + 1;
                else
                    r2 = mid2;
            }
            if (a[l2 - 1] == x)
            {
                tol += l2 - l; // 由于此时的 l2 是“最后一次出现的位置” + 1,故直接相减即可
            }
        }
    }
    cout << tol;
    return 0;
}

如果有错误,欢迎各位神犇指出。orz orz % %

举报

相关推荐

0 条评论