二分练习题2 查找大于等于x的最小元素 题解

题目描述

现在告诉你一个长度为 (n) 的有序数组 (a_1, a_2, ..., a_n) ,以及 (q) 次询问,每次询问会给你一个数 (x) ,对于每次询问,你需要输出数组 (a) 中大于等于 (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) ,如果数组 (a) 中存在大于等于 (x) 的元素,则输出数组 (a) 中满足大于等于 (x) 条件的所有元素中最小的元素;否则输出“-1” 。每个输出结果占单独的一行。

样例输入

5
1 3 5 7 9
3
2
9
11

样例输出

3
9
-1

题目分析

本题涉及算法:二分。
因为数组是按照单调非递增的顺序给我们的(即满足 (a_i le a_{i+1}) ),所以我们按照如下方式进行二分:
首先我们开一个变量 (L = 1) 用于表示初始时自变量(数组坐标)的左边界;在一个变量 (L = n) 用于表示初始时自变量(数组坐标)的右边界。
我们还需要开一个变量 (res) 用于存储答案(即大于等于 (x) 的最大的数),初始时 (res = -1) (如果结束的时候 (res) 还是 (-1) 则说明没有符合要求的答案)。
然后只要满足 (L le R) 条件,我们就循环执行如下操作:
开一个变量 (mid) 并令 (mid = (L+R)/2) ,然后判断:

  • 如果 (a[mid] ge x) ,说明这个 (a[mid]) 是满足 (ge x) 的当前最优解;所以我们需要将 (res) 更新为 (mid) ,同时执行 (R = mid-1) 。因为当前最优解并不一定是最终最优解,(a[mid] ge x) 能够说明的是 ([mid,R]) 范围内的所有元素都 (ge x) ,但是并不能说明 ([L, mid-1]) 范围内是否还存在比 (a[mid]) 更小的元素同样 (ge x) ,所以我们还是要继续循环的进左半边去查找(所以才需要执行 (R = mid -1) 操作)。
  • 如果 (a[mid] lt x) ,说明 (a[L])(a[mid]) 范围内的所有元素都 (lt x) ,所以我们只需要执行 (L = mid +1) 进右半边继续查找。

这样,当循环结束的时候(不满足 (L le R) 条件则循环就结束了):

  • 如果 (R = -1) ,说明没有找到答案(因为只要找到答案 (res) 就会更新,如果到循环结束的时候 (res) 还是等于 (-1) 则说明一个满足要求的答案都没有找到过);
  • 否则,(res) 对应的就是大于等于 (x) 的最小元素的坐标,我们直接输出 (a[res]) 即可。

这里需要注意的是:一旦找到了当前最优解,我就更新 (res)(mid) (令 (res) 记录最优解的自变量);但是其实我们也可以更新 (res)(a[mid])(令 (res) 记录最优解的应变量)。之所以我更习惯用 (res) 记录自变量的原因是:可以直接通过自变量得到应变量,而不能直接通过应变量得到自变量,所以使用 (res) 记录自变量会好一些。

实现代码如下:

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

// solve函数用于返回大于等于x的最小元素
int solve(int x) {
    int L = 1, R = n, res = -1;
    while (L <= R) {
        int mid = (L + R) / 2;
        if (a[mid] >= x) {
            res = mid;
            R = mid - 1;
        }
        else L = mid + 1;
    }
    if (res == -1) return -1; // 如果循环结束res==-1,说明没有找到答案
    return a[res];  // 因为res存的是最优解的坐标,所以返回a[res]
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    cin >> q;
    while (q --) {
        cin >> x;
        cout << solve(x) << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zifeiynoip/p/11450622.html