突破编程_C++_查找算法(分块查找)

1 算法题 :使用分块算法在有序数组中查找指定元素

1.1 题目含义

在给定一个有序数组的情况下,使用分块查找算法来查找数组中是否包含指定的元素。分块查找算法是一种结合了顺序查找和二分查找思想的算法,它将有序数组划分为若干个块,每个块内的元素不必有序,但块与块之间必须保持有序。首先通过块之间的有序性来快速定位到目标元素可能存在的块,然后在该块内进行顺序查找。

1.2 示例

示例 1:
输入:

  • 有序数组:[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]
  • 块大小:5
  • 目标元素:17

输出:

  • 7

说明:

  • 数组被划分为 3 个块:[1, 3, 5, 7, 9]、[11, 13, 15, 17, 19] 和 [21, 23, 25, 27, 29]。通过比较块的首个元素,可以确定目标元素 17 在第二个块中。然后在该块内进行顺序查找,找到元素 17 的位置为 7(从 0 开始计数)。

示例 2:
输入:

  • 有序数组:[1, 4, 6, 9, 13, 16, 19, 22, 25, 28]
  • 块大小:4
  • 目标元素:10

输出:

  • -1

说明:

  • 数组被划分为 3 个块:[1, 4, 6, 9]、[13, 16, 19, 22] 和 [25, 28]。通过比较块的首个元素,可以确定目标元素 10 不在任何一个块中,因此整个数组中也不存在该元素。

示例 3:
输入:

  • 有序数组:[]
  • 块大小:10
  • 目标元素:50

输出:

  • -1

说明:

  • 有序数组为空,50 不存在于有序数组中,返回 -1。

2 解题思路

2.1 简单分块查找

(1)确定块数:

首先,根据给定的块大小,计算数组可以分成的块数。如果数组长度不是块大小的整数倍,则最后一个块的大小可能会小于块大小。

(2)定位目标块:

遍历数组中的块,通过比较每个块的首个元素和目标元素的大小关系,确定目标元素可能所在的块。如果目标元素小于当前块的首个元素,则目标元素不可能在当前块及之后的块中,可以提前结束遍历。

(3)块内顺序查找:

在定位到的目标块内,使用顺序查找算法来查找目标元素。从目标块的起始位置开始,逐个比较元素直到找到目标元素或遍历完整个块。

(4)返回结果:

如果找到了目标元素,则返回其在数组中的位置(索引)。如果遍历完所有块都没有找到目标元素,则返回表示未找到的标志(如-1)。

2.2 优化块内查找

这种思路在第一种的基础上,对块内查找进行了优化。

(1)确定块数和索引映射:

首先,像第一种思路一样确定块数。然后,可以建立一个索引映射关系,将每个元素映射到其所属的块和块内的相对位置。这样可以在定位到目标块后,直接计算出目标元素在块内的相对位置,减少不必要的比较操作。

(2)定位目标块:

这一步与第一种思路相同,通过比较块的首个元素和目标元素的大小关系,确定目标元素可能所在的块。

(3)块内直接定位:

利用索引映射关系,直接计算出目标元素在块内的相对位置。然后,通过该相对位置访问数组元素,检查是否为目标元素。

(4)返回结果:

如果找到了目标元素,则返回其在数组中的位置(索引)。如果遍历完所有块都没有找到目标元素,则返回表示未找到的标志(如-1)。

3 算法实现代码

3.1 简单分块查找

如下为算法实现代码:

#include <iostream>  
#include <vector>  
#include <cmath>  
#include <algorithm>  class Solution
{
public:// 分块查找算法实现  int blockSearch(const std::vector<int>& arr, int blockSize, int target) {int n = arr.size();int blockNum = (n + blockSize - 1) / blockSize; // 计算块数,向上取整  // 遍历块,定位目标元素可能所在的块  for (int i = 0; i < blockNum; ++i) {int blockStart = i * blockSize;int blockEnd = std::min(blockStart + blockSize, n); // 块内最后一个元素的索引  // 如果目标元素小于当前块的最小值,则目标元素不可能在当前块及之后的块中  if (target < arr[blockStart]) {break;}// 如果目标元素大于当前块的最大值,则继续查找下一个块  if (target > arr[blockEnd - 1]) {continue;}// 在目标块内进行顺序查找  for (int j = blockStart; j < blockEnd; ++j) {if (arr[j] == target) {return j; // 返回目标元素在数组中的位置  }}}return -1; // 未找到目标元素  }
};

这段代码首先计算了块数 blockNum,然后遍历每个块,通过比较块的首个元素 arr[blockStart] 和最后一个元素 arr[blockEnd - 1] 与目标元素 target 的大小关系,来确定目标元素可能所在的块。如果目标元素小于当前块的最小值,则它不可能在当前块及之后的块中,可以提前结束遍历。如果目标元素在当前块内,则在该块内进行顺序查找,直到找到目标元素或遍历完整个块。如果遍历完所有块都没有找到目标元素,则返回 -1 表示未找到。

调用上面的算法,并得到输出:

int main() 
{Solution s;std::vector<int> arr = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 };int blockSize = 5; // 块大小  int target = 17; // 目标元素  int index = s.blockSearch(arr, blockSize, target);if (index != -1) {std::cout << "Element found at index: " << index << std::endl;}else {std::cout << "Element not found in the array." << std::endl;}return 0;
}

上面代码的输出为:

Element found at index: 8

3.2 优化块内查找

如下为算法实现代码:

#include <iostream>  
#include <vector>  
#include <cmath>  
#include <algorithm>  
#include <unordered_map>  class Solution
{
public:// 分块查找算法实现  int blockSearch(const std::vector<int>& arr, int blockSize, int target) {int n = arr.size();int blockNum = (n + blockSize - 1) / blockSize; // 计算块数,向上取整  std::unordered_map<int, std::pair<int, int>> blockIndicesAndOffsets; // 存储块索引和块内偏移量  computeBlockIndicesAndOffsets(arr, blockSize, blockIndicesAndOffsets);// 遍历块,定位目标元素可能所在的块  for (int i = 0; i < blockNum; ++i) {int blockStart = i * blockSize;int blockEnd = std::min(blockStart + blockSize, n); // 块内最后一个元素的索引  // 如果目标元素小于当前块的最小值,则目标元素不可能在当前块及之后的块中  if (target < arr[blockStart]) {break;}// 如果目标元素大于当前块的最大值,则继续查找下一个块  if (target > arr[blockEnd - 1]) {continue;}// 检查目标元素是否在块内,并返回其位置  auto it = blockIndicesAndOffsets.find(target);if (it != blockIndicesAndOffsets.end() && it->second.first == i) {return blockStart + it->second.second; // 返回目标元素在数组中的位置  }}return -1; // 未找到目标元素 }private:// 计算并存储每个元素的块索引和块内偏移量  void computeBlockIndicesAndOffsets(const std::vector<int>& arr, int blockSize,std::unordered_map<int, std::pair<int, int>>& blockIndicesAndOffsets) {int n = arr.size();for (int i = 0; i < n; ++i) {int blockIndex = i / blockSize;int offset = i % blockSize;blockIndicesAndOffsets[arr[i]] = { blockIndex, offset };}}
};

在这个代码中,computeBlockIndicesAndOffsets 函数用于计算并存储每个元素的块索引和块内偏移量。optimizedBlockSearch 函数首先通过遍历块来定位目标元素可能所在的块,然后直接检查目标元素是否在预计算的块索引和偏移量映射中,并且其块索引与当前遍历的块索引相匹配。如果找到匹配项,则直接返回目标元素在数组中的位置。

注意:这种方法只适用于数组不会改变的情况,因为一旦数组发生变化,就需要重新计算块索引和偏移量。此外,如果数组非常大或者元素非常多,存储块索引和偏移量映射可能会消耗大量内存。因此,在实际应用中,需要根据具体情况权衡这种优化方法的利弊。

4 测试用例

以下是针对上面算法的测试用例,基本覆盖了各种情况:

(1)基础测试用例
输入:数组 arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29},块大小 blockSize = 5,目标元素 target = 17
输出:找到目标元素 17,位置为 8
说明:目标元素位于第三个块内,算法能够正确找到其位置。

(2)边界测试用例
输入:数组 arr = {1, 3, 5, 7, 9},块大小 blockSize = 3,目标元素 target = 1
输出:找到目标元素 1,位置为 0
说明:目标元素位于数组的第一个元素,算法能够正确处理边界情况。

输入:数组 arr = {1, 3, 5, 7, 9},块大小 blockSize = 3,目标元素 target = 9
输出:找到目标元素 9,位置为 4
说明:目标元素位于数组的最后一个元素,算法能够正确处理边界情况。

(3)块内查找测试用例
输入:数组 arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29},块大小 blockSize = 5,目标元素 target = 23
输出:找到目标元素 23,位置为 12
说明:目标元素位于第三个块内,但不是块的首个或末尾元素,算法能够在块内正确找到目标元素。

(4)未找到目标元素测试用例
输入:数组 arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29},块大小 blockSize = 5,目标元素 target = 30
输出:未找到目标元素 30
说明:目标元素不在数组中,算法能够正确处理未找到目标元素的情况。

(5)空数组测试用例
输入:数组 arr = {},块大小 blockSize = 5,目标元素 target = 1
输出:未找到目标元素 1
说明:数组为空,算法能够正确处理空数组的情况。

(6)单个块测试用例
输入:数组 arr = {1, 2, 3, 4, 5},块大小 blockSize = 5,目标元素 target = 3
输出:找到目标元素 3,位置为 2
说明:整个数组只包含一个块,算法能够正确处理单个块的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/769548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码标识含义

START_RELATION ‘开始关系’ START_TIME ‘开始时间’ NO_OP_TIME ‘无操作时间’ NO_OP_RELATION ‘无操作关系’ NO_OP_ENTITY ‘无操作实体’ DUMMY_RELATION ‘虚拟关系’ DUMMY_ENTITY ‘虚拟实体’ DUMMY_TIME ‘虚拟时间’ DUMMY_RELATION_ID 0 START_RELATI…

“神器”巩膜镜,为屈光不正及难治角膜病患者带来希望!

“我不想再戴回框架眼镜了&#xff0c;但是由于角膜疾病问题&#xff0c;我曾戴普通隐形眼镜和RGP都会出现极强的异物感&#xff0c;非常不舒服&#xff01;现在我该怎么办呢&#xff1f;”四川眼科医院门诊&#xff0c;张女士疑惑地问到。 28岁的张女士是一名圆锥角膜患者&am…

Pixelmator Pro:专业级图像编辑,触手可及mac版

Pixelmator Pro是一款功能强大的图像编辑软件&#xff0c;专为Mac操作系统设计。它拥有直观的界面和丰富的工具&#xff0c;能够满足用户各种图像处理需求。 Pixelmator Pro软件获取 首先&#xff0c;Pixelmator Pro支持多种文件格式&#xff0c;包括JPEG、PNG、GIF、BMP、TIF…

【包远程安装运行】SpringBoot+Mysql实现的美食分享菜谱制作平台+演示视频+开发文档(论文模板)

今天发布的是由【猿来入此】的优秀学员独立做的一个基于springboot脚手架的美食分享菜谱制作平台系统&#xff0c;该系统分为前台和后台&#xff0c;多用户分享平台。主要实现了 除脚手架功能以外下面是系统的功能&#xff1a; 前台普通用户&#xff1a;注册、登录、首页、美食…

C++ C++11

一.C11 1.1 C11的简介 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C98标准中的漏洞进行修复&#xff0c;语言的核心部分则没有改动&#xff0c;因此人们习惯性的把两…

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(三)—— 随机梯度下降

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 这篇文章中&#xff0c;咱们将使用Keras和TensorFlow…

5.5.8、【AI技术新纪元:Spring AI解码】Pinecone

Pinecone 本节将指导您如何设置 Pinecone VectorStore 以存储文档嵌入并执行相似性搜索。 Pinecone 是什么? Pinecone 是一款流行的基于云端的向量数据库,它允许您高效地存储和搜索向量。 准备工作 Pinecone 账户:首先,请注册 Pinecone 账户。 Pinecone 项目:注册后,…

GPT神器级插件Code Interpreter

自去年 3 月份以来&#xff0c;人们对 GPT-4 API 的兴趣激增&#xff0c;“有数百万开发人员请求访问”。OpenAI 在一篇博客文章中&#xff0c;分享了使用 GPT-4 正在进行的一系列令人兴奋的创新&#xff0c;并阐明了未来的愿景&#xff1a;未来基于聊天的大模型可以用在任意的…

第29章 常用模块的使用

第29章 常用模块的使用 本章主要介绍 ansible 中最常见模块的使用。 ◆ 文件管理模块 ◆ 软件包管理模块 ◆ 服务管理模块 ◆ 磁盘管理模块 ◆ 用户管理模块 ◆ 防火墙管理模块 文章目录 第29章 常用模块的使用29.1 shell 模块29.2 文件管理的 file 模块29.3 copy 和fetch模块…

每秒批量插入10000条数据到MySQL中,资源消耗(带宽、IOPS)有多少?

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容起因代码资源情况改造 &#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、…

LeetCode每日一题[c++]-322.零钱兑换

题目描述 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数量是无…

照片变动图怎么操作?一招在线转换

GIF动画是一种特殊的图像文件格式&#xff0c;它可以在一张图像中显示多个图像帧&#xff0c;并以循环播放的方式展示&#xff0c;从而实现动态效果。由于GIF格式的广泛支持和较小的文件大小&#xff0c;它成为了互联网上常见的动画格式之一。想要制作gif动画图片可以使用Gif制…

链动2+1模式 完全合法合规 不存在传销问题!!

在商业经营中&#xff0c;营销策略的巧妙运用对于提升产品销量和扩大品牌影响力至关重要。然而&#xff0c;企业在制定和执行营销策略时&#xff0c;必须严格遵循法律法规&#xff0c;以免陷入法律风险。本文将着重探讨链动21模式的法律要素&#xff0c;以论证其合规性。 一、链…

穿越地心:3D可视化技术带你领略地球内部奇观

在广袤无垠的宇宙中&#xff0c;地球是一颗充满生机与奥秘的蓝色星球。我们每天都生活在这颗星球上&#xff0c;感受着它的温暖与恩赐&#xff0c;却往往忽略了它深邃的内部世界。 想象一下&#xff0c;你能够穿越时空&#xff0c;深入地球的核心&#xff0c;亲眼目睹那些亿万年…

nodeJs中实现连表查询

nodeJs中实现连表查询 router.post(/getOrder, async function(req, res, next) {let userId req.body.phone;let sql select * from orders where userId?;let orders await new Promise((resolve, reject) > {connection.query(sql, [userId], function(error, resul…

MapReduce配置和Yarn的集群部署

一、集群环境&#xff0c;还是如下三台服务器 192.168.32.101 node1192.168.32.102 node2192.168.32.103 node3 二、YARN架构 YARN&#xff0c;主从架构&#xff0c;有2个角色 主&#xff08;Master&#xff09;角色&#xff1a;ResourceManager从&#xff08;Slave&#x…

【Redis教程0x04】详解Redis的4个高级数据类型

引言 在【Redis教程0x03】中&#xff0c;我们介绍了Redis中常用的5种基础数据类型&#xff0c;我们再来回顾一下它们的使用场景&#xff1a; String&#xff1a;存储对象、url、计数、分布式锁&#xff1b;List&#xff1a;消息队列&#xff1b;Hash&#xff1a;存储对象、购…

ChatGPT论文指南|ChatGPT论文写作过程中6个润色与查重口诀!【建议收藏】

点击下方▼▼▼▼链接直达AIPaperPass &#xff01; AIPaperPass - AI论文写作指导平台 公众号原文▼▼▼▼&#xff1a; ChatGPT论文指南|ChatGPT论文写作过程中6个润色与查重口诀&#xff01;【建议收藏】 目录 1.润色与查重口诀 2.AIPaperPass智能论文写作平台 论文完成…

商机在线互动营销— —Pushmall智能AI数字名片

商机在线互动营销— —Pushmall智能AI数字名片 开发计划 2024年2月开发计划&#xff1a; 1、优化名片注册、信息完善业务流程&#xff1b; 2、重构供应信息、需求信息发布。 3、会员名片地理位置服务优化‘ 4、企业名片&#xff1a;员工管理优化 5、CRM客户资源管理设计。 已…

基础小白十天学会linux------linux的指令

1.图形界面使用shell命令 2.字符界面使用shell命令 3.shell命令一般格式&#xff1a;命令名选项参数&#xff0c;命令名一般是英文全称的缩写&#xff0c;选项前导符以-、--开头&#xff0c;还可以没有前导符 字符界面截屏要求&#xff1a; 1) 启动计算机&#xff0c;以超级用…