当前位置: 首页 > news >正文

整数二分思路详解

题目描述

给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。
如果数组中不存在该元素,则返回“-1 -1”。
输入格式
第一行包含整数n和q,表示数组长度和询问个数。
第二行包含n个整数(均在1~10000范围内),表示完整数组。
接下来q行,每行包含一个整数k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回“-1 -1”。
数据范围
1≤n≤100000
1≤n≤100000

1≤q≤10000
1≤q≤10000

1≤k≤10000
1≤k≤10000

样例

输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1

分析:

用二分去查找元素要求数组拥有两段性,即数组中的元素存在分界线,给定条件可以将集合中元素分为两部分,一部分满足条件,一部分不满足条件。对本题而言,一个包含重复元素的有序序列,要求输出某元素出现的起始位置和终止位置,翻译一下就是:在数组中查找某元素,找不到就输出1−1的第一个位置,较为简单:

int l = 0, r = n - 1;
while (l < r) {int mid = l + r >> 1;if (a[mid] < x)  l = mid + 1;else    r = mid;
}

a[mid]<xa[mid]<x的最后一个位置,便不容易了:

int l1 = l, r1 = n;
while (l1 + 1 < r1) {int mid = l1 + r1 >> 1;if (a[mid] <= x)  l1 = mid;else    r1 = mid;
}

要查找不大于x的最后一个位置:

a[mid]<=xa[mid]<=x是开区间。上面这种写法修改了循环条件使得二分不会死循环,修改了区间的开闭性使得不会查找错误。另一种解决办法就是:

int l = 0, r = n - 1;
while (l < r){int mid = l + r + 1 >> 1;if (a[mid] <= x) l = mid;else r = mid - 1;}

不修改循环终止条件,想办法解决死循环的问题,首先想下为什么查找不小于xx.

是否还有其他办法既不修改区间的开闭性和循环终止条件,又不用上取整呢?答案是肯定的。

int l1 = l, r1 = n - 1;
while (l1 < r1) {int mid = l1 + r1 >> 1;if (a[mid] <= x)  l1 = mid + 1;else    r1 = mid - 1;
}
printf("%d %d\n", l, l1 - (a[l1] == x ? 0 : 1));

我们之所以会进行第二轮查找不大于xx,所以加上这个判断就可以解决该问题了。这也是二分程序可能遇见的第三种问题,当左右指针都移动时,待查找元素处在元素末尾会引起查找错误。总的代码如下:

#include <iostream>
using namespace std;
const int maxn = 100005;
int n, q, x, a[maxn];
int main() {scanf("%d%d", &n, &q);for (int i = 0; i < n; i++)    scanf("%d", &a[i]);while (q--) {scanf("%d", &x);int l = 0, r = n - 1;while (l < r) {int mid = l + r >> 1;if (a[mid] < x)  l = mid + 1;else    r = mid;}if (a[l] != x) {printf("-1 -1\n");continue;}int l1 = l, r1 = n;while (l1 + 1 < r1) {int mid = l1 + r1 >> 1;if (a[mid] <= x)  l1 = mid;else    r1 = mid;}printf("%d %d\n", l, l1);}return 0;
}
http://www.lryc.cn/news/22439.html

相关文章:

  • 基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文
  • 手动添加 Grub 启动项
  • 工人搬砖-课后程序(JAVA基础案例教程-黑马程序员编著-第八章-课后作业)
  • 深度学习中backbone、head、neck等概念
  • 华为OD机试用Python实现 -【Linux 发行版的数量】(2023-Q1 新题)
  • Http报文解析
  • Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目
  • TIA博途Wincc中自定义配方画面的具体方法示例
  • Java反射系列--方法大全
  • LeetCode 169. 多数元素
  • 来了,metaIPC1.0
  • WireShark如何进行USB包协议分析
  • 蒙特卡洛随机模拟
  • Android从屏幕刷新到View的绘制(三)之Handler异步消息与同步屏障
  • 最新版axios@1.3.x取消请求-AbortController-初体验-番茄出品
  • Git的简述
  • webpack实战,手写loader和plugin
  • STM32CubeMX按键模块化 点灯
  • C#专栏目录(长期更新)
  • BurpSuite配置抓取HTTPS数据包
  • 图片转base64格式返回给前端,前端如何展示?
  • C++入门知识【超详解】
  • 零基础、非计算机系学Python该如何上手?
  • 关于 vue3 模板引用
  • Redis | 安装Redis和启动Redis服务
  • 博客要考虑的最佳WordPress主题
  • C 学习笔记 —— 函数指针
  • FastDDS-3. DDS层
  • 9.2 IGMPv2
  • 巨头混战,抢着“兜底”自动驾驶安全