• 二分练习题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;
    }
    
  • 相关阅读:
    Linux查看程序端口占用情况
    详解大端模式和小端模式
    HDFS之二:HDFS文件系统JavaAPI接口
    HBase之四--(1):Java操作Hbase进行建表、删表以及对数据进行增删改查,条件查询
    HBase之七:事务和并发控制机制原理
    HBase源码分析:HTable put过程
    QueryPerformanceFrequency使用方法--Windows高精度定时计数
    mongoDB的基本使用----飞天博客
    Android使用DOM生成和输出XML格式数据
    黑马程序猿_Java 代理机制学习总结
  • 原文地址:https://www.cnblogs.com/zifeiynoip/p/11450622.html
Copyright © 2020-2023  润新知