P2249 【深基13.例1】查找(洛谷,C++,二分法)

题目描述

输入n个不超过10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数a1,a2,...,an,然后进行m次询问。对于每次询问,给出一个整数q,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出-1 。

输入格式

第一行 2个整数n和m,表示数字个数和询问次数。

第二行n个整数,表示这些待查询的数字。

第三行m个整数,表示询问这些数字的编号,从 11 开始编号。

输出格式

输出一行,m个整数,以空格隔开,表示答案。

输入样例

11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6

输出样例

1 2 -1 

说明/提示

数据保证,1 <= n <= 10^6,0 <= ai,q <= 10^9,1 <= m <= 10^5

本题输入输出量较大,请使用较快的 IO 方式。

注:虽然这里要使用较快的IO方式,但是不能通过getline(cin, str)而只能通过减少I/O次数(如Input与Processed一同进行),因为每位数字都算作一个字符,占用的长度难以确认

解题思路:

核心解题思路:二分搜索

以下为简单的二分搜索的实现

#include <iostream>
using namespace std;
​
int main()
{
    int num_array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int right = 9, left = 0, middle;
    int acquire;
    bool acquire_result = false;
    cin >> acquire;
    while (right >= left)
    {
        middle = (right + left) / 2;
        if (num_array[middle] == acquire)
        {
            acquire = true;
            break;
        }
        else if (num_array[middle] > acquire)
        {
            right = middle - 1;
        }
        else
        {
            left = middle + 1;
        }
    }
    if (acquire_result)
    {
        cout << "True" << endl;
    }
    else
    {
        cout << "False" << endl;
    }
    return 0;
}

采用IPO思路实现代码:

(1)I:

创建两个数组,分别用于存储n个数字和m次询问的结果

用for循环输入n个数字

(2)P和O:

用for循环询问m次,每次得到的结果存储到数组中,统一输出

每次循环键入一个值,用二分法搜索

搜索到指定值以后,再次用while循环调用内层二分法,以确保得到最早出现的位置

代码实现如下:

#include <iostream>
using namespace std;
​
//考虑到边界条件,前后各留出一个冗余位
int num_array[int(1e6) + 1 + 1] = { -1 };//n个数字
int num_array_q[int(1e5) + 1] = { -1 };//m次询问结果
​
int main()
{
    int n, m;
    int i, j, z, middle;//循环和二分控制符
    int pos;//获取最早出现位置,若未搜索到,则为-1
    std::cin.tie(nullptr);
    cin >> n >> m;
    for (i = 1; i <= n; i++)//循环输入n个数字
    {
        cin >> num_array[i];
    }
    for (z = 1; z <= m; z++)//循环进行m次询问
    {
        cin >> num_array_q[z];
        //二分搜索开始
        i = 1, j = n, pos = -1;
        while (i <= j)
        {
            middle = (i + j) / 2;
            if (num_array[middle] == num_array_q[z])
            {
                while (num_array_q[z] == num_array[middle - 1])//while循环条件:只要middle的左侧仍有相同元素,就继续二分查找
                {
                    int inner_j = middle - 1;//内层二分的右
                    int inner_middle;//内层二分的middle
                    while (i <= inner_j)
                    {
                        inner_middle = (i + inner_j) / 2;
                        if (num_array[inner_middle] == num_array_q[z])
                        {
                            middle = inner_middle;
                            break;//找到内层middle,赋值给外层middle,退出,进入下一轮内层二分
                        }
                        else if (num_array[inner_middle] > num_array_q[z])
                        {
                            inner_j = inner_middle - 1;
                        }
                        else
                        {
                            i = inner_middle + 1;
                        }
                    }
                }
                pos = middle;
                break;
            }
            else if (num_array[middle] > num_array_q[z])
            {
                j = middle - 1;
            }
            else
            {
                i = middle + 1;
            }
        }
        cout << pos << ' ';
    }
    return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WitheredSakura_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值