二分练习题1 查找元素 题解

题目描述

现在告诉你一个长度为 \(n\) 的有序数组 \(a_1, a_2, ..., a_n\) ,以及 \(q\) 次询问,每次询问会给你一个数 \(x\) ,对于每次询问,你需要确定在数组中是否存在某一个元素 \(a_i = x\)

输入格式

输入的第一行包含一个整数 \(n(1 \le n \le 100000)\) ,用于表示数组中元素的个数。
输入的第二行包含 \(n\) 个整数,两两之间有一个空格,用于表示数组中的元素 \(a_1, a_2, ..., a_n(1 \le a_i \le 10^9,并且 a_1 \le a_2 \le ... \le a_n)\)
输入的第三行包含一个整数 \(q(1 \le q \le 100000)\) ,用于表示询问的次数。
接下来 \(q\) 行,每行包含一个整数 \(x(1 \le x \le 10^9)\) ,表示要询问的数。

输出格式

对于每一次询问的 \(x\) ,如果数组中存在元素等于 \(x\) ,则输出 “YES” ; 否则,输出 “NO”。每个输出结果占单独的一行。

样例输入

5
1 3 5 7 9
3
1
2
3

样例输出

YES
NO
YES

题目分析

本题涉及算法:二分。
因为这道题目告诉我们数组元素是按照单调非递减的顺序输入的(即 \(a_i \le a_{i+1}\) ),所以我们令自变量为坐标 \(i\) ,应变量为数组元素 \(a_i\) 进行二分。
我们的程序中将编写一个 bool solve(int x) 函数,它用于判断数组中是否存在值为 \(x\) 的元素。其判断逻辑为:
一开始设 \(L = 1\)(数组的左边界的坐标),设 \(R = n\)(数组的右边界的坐标),然后只要满足 \(L \le R\) 的条件,我就令 \(mid = (L+R)/2\)(也就是 \(L\)\(R\) 的中位数),判断 \(a[mid]\) 是否等于 \(x\) ,会有三种情况:

  • 如果 \(a[mid] = x\) ,找到了,返回true;
  • 如果 \(a[mid] \lt x\) ,则 \(a[mid]\) 及它左边范围(即 \([L,mid]\) 范围)内的所有元素都 \(\lt x\) ,令 \(L = mid + 1\) ,进右半边的区域继续进行搜索;
  • 如果 \(a[mid] \gt x\) ,则 \(a[mid]\) 及它右边范围(即 \([mid,R]\) 范围)内的所有元素都 \(\gt x\) ,令 \(R = mid - 1\) ,进左半边的区域继续进行搜索。

当退出上面的循环操作(即已经不满足 \(L \le R\) 条件)时,如果我们还没有找到等于 \(x\) 的元素,则说明在数组 \(a\) 中不存在等于 \(x\) 的元素。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, a[maxn], q, x;

bool solve(int x) {
    int L = 1, R = n;
    while (L <= R) {
        int mid = (L + R) / 2;
        if (a[mid] == x) return true;
        else if (a[mid] > x)
            R = mid - 1;
        else // a[mid] < x
            L = mid + 1;
    }
    return false;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    cin >> q;
    while (q --) {
        cin >> x;
        puts( solve(x) ? "YES" : "NO" );
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zifeiynoip/p/11450618.html