整数二分算法

news/2025/2/26 0:08:22

例题:

给定一个按照升序排列的长度为 n 的整数数组,以及 q个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0开始计数)。

如果数组中不存在该元素,则返回 -1 -1

输入格式

第一行包含整数 n 和 q,表示数组长度和询问个数。第二行包含 n 个整数(均在 1∼10000范围内),表示完整数组。接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式

共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1

数据范围

1≤n≤100000
1≤q≤10000
1≤k≤10000

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

算法模板:

整数二分的本质不是单调性,只要可将区间依据是否满足某种性质一分为二,就可以用二分


bool check(int x) {} //检查x是否满足某种性质

//区间[l, r]被划分为[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r) {
    while (l < r) {
    	int mid = (l + r) >> 1;
    	if (check(mid)) r = mid;
    	else l = mid + 1;
    }
    return l;
}

//区间[l, r]被划分为[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r) {
	while (l < r) {
		int mid = (l + r + 1) >> 1; //因为整数/2存在向下取整问题,如果这里不加1,更新时会出现l = mid = l的情况【如l = r - 1时】会陷入死循环 
		if (check(mid)) l = mid; 
		else r = mid - 1;
	}
	return l;
} 

区间如何更新?

 参考题解

/*整数二分算法*/
#include <iostream>
#include <vector>

using namespace std;

int main () {
	int n, q; //数组长度和询问个数
	cin >> n >> q;
	
	vector<int> array (n);
	for(int i = 0; i < n; i++) {
		cin >> array[i];
	}
	
	while(q--) {
		int query;
		cin >> query;
		
		int l = 0, r = n - 1;
		while(l < r) {
			int mid = (l + r) >> 1;
			if(array[mid] >= query) { //找起始位置时,将性质定义为>=x 
				r = mid;
			}else {
				l = mid + 1;
			}
		}
		
		if(array[l] != query) {
			cout << "-1 -1" << '\n';
			continue; 
		}
		
		cout << l << ' ';
		
		l = 0, r = n - 1;
		while(l < r) {
			int mid = (l + r + 1) >> 1;
			if(array[mid] <= query) { //找结束位置时,将性质定义为<=x 
				l = mid;
			}else {
				r = mid - 1;
			}
		}
		
		cout << l << '\n';
	}
	return 0;
}

总结 

重点在于画图想清楚要找的分界点应该使用什么性质,以这道题为例,刚开始一直想着用<query来找,但就感觉这样不太对劲,画图后才清晰地理解为什么要用>=query

参考:AcWing关于二分的讲解


http://www.niftyadmin.cn/n/5866983.html

相关文章

5G网络切片辨析(eMBB,mMTC,uRLLC)

URLLC有三大应用场景&#xff0c;分别是eMBB&#xff08;增强型移动宽带&#xff09;、uRLLC&#xff08;高可靠低延时通信&#xff09;和mMTC&#xff08;海量机器通信&#xff09;。 增强型移动宽带&#xff08;eMBB&#xff09;&#xff1a;需要关注峰值速率&#xff0c;容…

【GESP】C++二级真题 luogu-b3955, [GESP202403 二级] 小杨的日字矩阵

GESP二级真题&#xff0c;多层循环、分支语句练习&#xff0c;难度★✮☆☆☆。 题目题解详见&#xff1a;https://www.coderli.com/gesp-2-luogu-b3955/ 【GESP】C二级真题 luogu-b3955, [GESP202403 二级] 小杨的日字矩阵 | OneCoderGESP二级真题&#xff0c;多层循环、分支…

unity学习53:UI的子容器:面板panel

目录 1 UI的最底层容器&#xff1a;canvas 1.1 UI的最底层容器&#xff1a;canvas 1.2 UI的合理结构 2 UI的子容器&#xff1a;面板panel 2.1 创建panel 2.2 面板的本质&#xff1a; image &#xff0c;就是一个透明的图片&#xff0c;1个空容器 3 面板的属性 4 面板的…

大数据平台上的机器学习模型部署:从理论到实

大数据平台上的机器学习模型部署&#xff1a;从理论到实践 大家好&#xff0c;我是Echo_Wish&#xff0c;一名专注于大数据领域的自媒体创作者。今天&#xff0c;我们将深入探讨大数据平台上的机器学习模型部署。随着数据量的爆炸式增长&#xff0c;如何在大数据平台上高效地部…

【LeetCode刷题之路】leetcode155.最小栈

LeetCode刷题记录 &#x1f310; 我的博客主页&#xff1a;iiiiiankor&#x1f3af; 如果你觉得我的内容对你有帮助&#xff0c;不妨点个赞&#x1f44d;、留个评论✍&#xff0c;或者收藏⭐&#xff0c;让我们一起进步&#xff01;&#x1f4dd; 专栏系列&#xff1a;LeetCode…

ubuntu新系统使用指南

1. 更新源 2. 配置rime 输入法 sudo apt install ibus-rimeibus-setup #打开配置界面添加雾凇拼音 cd ~/Documents/Tool/input_source/plumgit clone --depth 1 https://github.com/rime/plum plum #没有梯子就劝退cd plum/bash rime-install iDvel/rime-ice:others/recipe…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

电机控制的空间矢量调制 (SVPWM)

目录 概述 1 电机控制的空间矢量调制 (SVPWM)介绍 2 实现原理 2.1 设计要求 2.2 SVPWM 的实现 3 SVPWM的C语言 3.1 代码文件 3.2 STM32G4平台上验证 4 源代码文件 概述 本文主要介绍电机控制的空间矢量调制 (SVPWM)&#xff0c;空间矢量调制 (SVPWM) 是感应电机和永磁…