突破编程_C++_查找算法(插值查找)

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

1.1 题目含义

使用插值查找算法在有序数组中查找指定元素。插值查找是介于线性查找和二分查找之间的一种查找算法,它是基于二分查找的改进算法。插值查找的核心思想在于根据待查找元素的值在有序数组中的位置,利用数学公式计算出该元素在数组中的大致位置,从而缩小查找范围,提高查找效率。

1.2 示例

示例 1:

输入:

  • nums = [1, 3, 4, 7, 10, 12, 13, 16, 18, 20]
  • target = 7

输出: 3
说明: 7 存在于 nums 中,且其索引为 3。

示例 2:

输入:

  • nums = [1, 3, 4, 7, 10, 12, 13, 16, 18, 20]
  • target = 25

输出: -1
说明: 25 不存在于 nums 中,返回 -1。

示例 3:

输入:

  • nums = []
  • target = 0

输出: -1
说明: nums 为空,0 不存在于 nums 中,返回 -1。

2 解题思路

2.1 循环遍历实现

(1)初始化参数:

  • 确定有序数组 arr 和待查找元素 target。
  • 获取数组的长度 n。
  • 设置数组的起始索引 low 为 0,结束索引 high 为 n - 1。

(2)检查边界情况:

  • 如果 target 小于 arr[low] 或大于 arr[high],则 target 不在数组中,直接返回 -1。

(3)计算插值位置:

  • 使用插值公式计算 target 在数组中的大致位置 pos。插值公式通常如下:
pos = low + ((target - arr[low]) * (high - low) / (arr[high] - arr[low]))
  • 确保 pos 是一个合法的索引值,即它应在 low 和 high 之间。如果 pos 不合法,则将其限制在合法范围内。

(4)缩小查找范围(比较 arr[pos] 与 target):

  • 如果它们相等,返回 pos,因为找到了目标元素。
  • 如果 target 小于 arr[pos],则新的结束索引 high 更新为 pos - 1。
  • 如果 target 大于 arr[pos],则新的起始索引 low 更新为 pos + 1。

(5)循环查找:

  • 使用一个循环来重复上述步骤,直到找到目标元素或查找范围为空。
  • 在每次循环中,重新计算插值位置 pos 并根据比较结果更新查找范围。

(6)返回结果:

  • 如果在循环结束前找到了 target,则返回其索引。
  • 如果循环结束后仍未找到 target(即 low 大于 high),则返回 -1,表示 target 不在数组中。

2.2 递归实现

(1)初始化参数:

  • 确定有序数组 arr 和待查找元素 target。
  • 获取数组的长度 n。
  • 设置数组的起始索引 low 为 0,结束索引 high 为 n - 1。

(2)检查边界情况:

  • 如果 target 小于 arr[low] 或大于 arr[high],则 target 不在数组中,直接返回 -1。

(3)递归函数定义:

  • 定义一个递归函数 interpolationSearchRecursive,该函数接受当前查找范围的起始索引 low、结束索引 high、目标值 target 和数组 arr 作为参数。

(4)计算插值位置:

  • 使用插值公式计算 target 在数组中的大致位置 pos。插值公式通常如下:
pos = low + ((target - arr[low]) * (high - low) / (arr[high] - arr[low]))
  • 确保 pos 是一个合法的索引值,即它应在 low 和 high 之间。如果 pos 不合法,则将其限制在合法范围内。

(5)递归调用(比较 arr[pos] 与 target):

  • 如果它们相等,返回 pos,因为找到了目标元素。
  • 如果 target 小于 arr[pos],则在数组的左半部分(low 到 pos - 1)继续递归查找。
  • 如果 target 大于 arr[pos],则在数组的右半部分(pos + 1 到 high)继续递归查找。
  • 递归调用 interpolationSearchRecursive 函数,传入更新后的查找范围和目标值。

(6)递归终止条件:

  • 找到了目标元素,返回其索引。
  • 查找范围为空(即 low 大于 high),表示目标元素不在数组中,返回 -1。

(7)返回结果:

  • 根据递归函数返回的结果,输出目标元素是否存在于数组中以及它的索引。

3 算法实现代码

3.1 循环遍历实现

如下为算法实现代码:

#include <iostream>  
#include <string>  
#include <vector>  class Solution
{
public:int interpolationSearch(std::vector<int>& nums, int target) {int n = arr.size();  if (n <= 0) {  return -1;  // 空数组,返回-1  }  int low = 0, high = n - 1;  // 检查边界情况  if (target < arr[low] || target > arr[high]) {  return -1;  // 目标值不在数组范围内  }  while (low <= high && arr[low] <= target && arr[high] >= target) {  // 计算插值位置  int pos = low + static_cast<int>(  ((double)(high - low) / (arr[high] - arr[low]) * (target - arr[low]));  // 检查pos是否越界  if (pos < low || pos > high) {  pos = (pos < low) ? low : high;  }  // 比较arr[pos]与目标值  if (arr[pos] == target) {  return pos;  // 找到目标值,返回其索引  }  // 根据比较结果更新查找范围  if (arr[pos] < target) {  low = pos + 1;  } else {  high = pos - 1;  }  }  // 没有找到目标值  return -1;  }
};

这段代码首先检查数组的边界情况,然后进入一个循环,在循环中计算插值位置,并根据比较结果更新查找范围。循环会一直执行,直到找到目标元素或确定目标元素不在数组中。最后,返回找到的元素的索引或-1表示未找到。

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

int main() 
{Solution s;std::vector<int> arr = { 1, 3, 4, 7, 10, 12, 13, 16, 18, 20 };int target = 7;int index = s.interpolationSearch(arr, target);if (index != -1) {std::cout << "Element " << target << " found at index: " << index << std::endl;}else {std::cout << "Element " << target << " not found in the array." << std::endl;}return 0;
}

上面代码的输出为:

Element 7 found at index: 3

3.2 递归实现

如下为算法实现代码:

#include <iostream>  
#include <string>  
#include <vector>  class Solution
{
public:int interpolationSearch(std::vector<int>& nums, int target) {return interpolationSearchRecursive(nums, target, 0, nums.size() - 1);}private:int interpolationSearchRecursive(const std::vector<int>& nums, int target, int low, int high) {// 检查边界情况  if (low > high || target < nums[low] || target > nums[high]) {return -1;  // 目标值不在数组范围内  }if (low == high) {return (nums[low] == target) ? low : -1;  // 如果low和high相等,检查是否找到目标值  }// 计算插值位置  int pos = low + static_cast<int>(((double)(high - low) / (nums[high] - nums[low]) * (target - nums[low])));// 确保pos是合法索引  pos = (pos < low) ? low : (pos > high) ? high : pos;// 比较nums[pos]与目标值  if (nums[pos] == target) {return pos;  // 找到目标值,返回其索引  }else if (nums[pos] < target) {return interpolationSearchRecursive(nums, target, pos + 1, high);  // 在右半部分递归查找  }else {return interpolationSearchRecursive(nums, target, low, pos - 1);  // 在左半部分递归查找  }}
};

在这段代码中,interpolationSearchRecursive 成员函数函数是递归查找的主体,它接受数组 nums、目标值 target、当前查找范围的起始索引 low 和结束索引 high 作为参数。函数首先检查边界情况,然后计算插值位置,并递归地在左半部分或右半部分查找,直到找到目标值或确定目标值不在数组中。interpolationSearch 函数是外部调用接口,它初始化了查找范围并调用了递归函数。

4 测试用例

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

(1)基础测试用例
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 9
输出:4
说明:目标值 9 存在于数组中,位于索引 4 的位置。

(2)目标值不存在于数组中
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 2
输出:-1
说明:目标值 2 不存在于数组中。

(3)目标值位于数组开头
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 -1
输出:0
说明:目标值 -1 位于数组的开头,即索引 0 的位置。

(4)目标值位于数组末尾
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 12
输出:5
说明:目标值 12 位于数组的末尾,即索引 5 的位置。

(5)目标值位于数组中间
输入:数组 [-1, 0, 3, 5, 9, 12],目标值 3
输出:2
说明:目标值 3 位于数组的中间位置,即索引 2 的位置。

(6)空数组
输入:数组 [],目标值 9
输出:-1
说明:空数组不包含任何元素,因此无法找到目标值。

(7)数组只有一个元素
输入:数组 [9],目标值 9
输出:0
说明:数组只有一个元素,且该元素就是目标值,位于索引 0 的位置。

(8)数组中存在多个相同的目标值
输入:数组 [1, 2, 3, 3, 4, 5],目标值 3
输出:2 或 3
说明:数组中存在多个目标值 3,返回任意一个目标值的索引都是正确的。这里可以返回 2 或 3。

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

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

相关文章

Web前端依赖版本管理最佳实践

本文需要读者懂一点点前端的构建知识&#xff1a; 1. package.json文件的作用之一是管理外部依赖&#xff1b;2. .npmrc是npm命令默认配置&#xff0c;放在工程根目录。 Web前端构建一直都是一个不难&#xff0c;但是非常烦人的问题&#xff0c;在DevOps、CI/CD领域。 烦人的是…

Java的SPI机制与实例

Java的SPI机制与实例 是什么&#xff1f; SPI是一种JDK内置的服务提供发现的机制&#xff0c;能够启动框架扩展和替换组件&#xff0c;主要是被框架的开发人员使用&#xff0c;比如java.sql。Driver接口。Java机制的核心思想就是将装配的控制权转移到Java之外&#xff0c;核心…

HTTPS证书很贵吗?

首先&#xff0c;我们需要明确一点&#xff0c;HTTPS证书的价格并不是一成不变的&#xff0c;它受到多种因素的影响。其中最主要的因素包括证书的类型、颁发机构以及所需的验证级别。 从类型上来看&#xff0c;HTTPS证书主要分为单域名证书、多域名证书和通配符证书。单域名证书…

远程过程调用-buttonrpc源码解析1-序列化

分析buttonrpc中的序列化 源码提供了StreamBuffer类&#xff0c;该类继承自vector<char>&#xff0c;用来存储数据。 // 此处省略实现... class StreamBuffer : public vector<char> {};并提供了Serializer类&#xff0c;用来序列化数据。 // 此处省略部分实现..…

pta上的几个例题

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

1258:【例9.2】数字金字塔-----动态规划(递推)1

题目网址 1258&#xff1a;【例9.2】数字金字塔 首先解这道题我们第一眼想到是不是暴力&#xff0c;但是暴力的话是O(n!)的时间复杂度&#xff0c;很明显&#xff0c;会超时。那怎么办呢&#xff1f;不如我们把他分成若干子问题把&#xff0c;就像分治那样。 首先我们想得到答案…

vue2 项目中使用clipboard复制插件

需求&#xff0c;点击页面中的某一个按钮&#xff0c;复制文字。 npm install clipboard --save 在组件中使用 import Clipboard from clipboard html中的按钮 <div ref"main" class"main"><button click"copy">copy</button…

Android Studio实现内容丰富的安卓校园新闻浏览平台

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号070 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看新闻列表 3.查看新闻详情 4.评论新闻 5.收藏新闻 6…

解决VMware无法检测此光盘映像中的操作系统

今天我本想在VMware上安装一个win10系统&#xff0c;可是遇到“无法检测此光盘映像中的操作系统。您需要指定要安装的操作系统。”的错误。报错如下&#xff1a; 图一 遇到的问题 开始还以为是ISO文件有问题&#xff0c;重新下载了几个还是不行&#xff08;一个ISO文件好几个G&…

免费SSL证书Let‘sEncrypt安装

1. Let’sEncrypt说明&#xff1a; Lets Encrypt 是免费、开放和自动化的证书颁发机构由Linux基金会(Linux Foundation)进行日常管理维护&#xff0c;它为36.3亿个网站提供TLS证书的非盈利性证书颁发机构, 通过它我们可以免费申请网站证书&#xff0c;并您的网站上启用 HTTPS …

APP专项测试

一、介绍 APP测试除了功能测试外&#xff0c;还需要进行一些专项测试来发现更为深层的问题&#xff0c;这些问题主要是针对某个特殊方面进行&#xff0c;如安装卸载升级测试、兼容性测试、弱网测试、中断测试、流量测试、耗电量测试等。 二 、安装卸载升级测试 APP开发后&am…

联想拯救者刃7000K2024游戏电脑主机仅售6999元

这款联想拯救者刀锋7000K 2024游戏电脑主机在京东促销中售价仅为6999元&#xff0c;相比原价7499元有相当大的折扣。 这是一款功能强大的游戏电脑&#xff0c;配备了全新的 15-14400(F) 处理器和 RTX™ 4060 显卡&#xff0c;以及 16GB DDR5 内存和 1TB 固态硬盘。 外观方面&a…

如何有效地组织和管理自己的代码?

如何有效地组织和管理自己的代码&#xff1f; &#x1f9e9; &#x1f6e0;️ 如何有效地组织和管理自己的代码&#xff1f; &#x1f9e9;摘要引言正文1. 使用合适的目录结构2. 模块化设计3. 命名规范4. 版本控制 总结参考资料 博主 默语带您 Go to New World. ✍ 个人主页——…

3.Redis命令

Redis命令 Redis 根据命令所操作对象的不同&#xff0c; 可以分为三大类&#xff1a; 对 Redis 进行基础性操作的命令&#xff0c;对 Key 的操作命令&#xff0c;对 Value 的操作命令。 1.1 Redis 首先通过 redis-cli 命令进入到 Redis 命令行客户端&#xff0c;然后再运行下…

STM32基础--使用寄存器点亮流水灯

GPIO 简介 GPIO 是通用输入输出端口的简称&#xff0c;简单来说就是 STM32 可控制的引脚&#xff0c;STM32 芯片的 GPIO 引脚与外部设备连接起来&#xff0c;从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO被分成很多组&#xff0c;每组有 16 个引脚&#xf…

多源BFS

目录 算法原理 多源BFS步骤&#xff1a; 1、542. 01 矩阵 2、1020. 飞地的数量 3、1765. 地图中的最高点 4、1162. 地图分析 多源BFS&#xff08;Breadth-First Search&#xff0c;广度优先搜索&#xff09;是解决边权为1的多源最短路径问题的有效算法。在这种情况下&…

【模拟string函数的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 模拟string函数的实现 浅拷贝 深拷贝 vs和g下string结构的说明 总结 前言 模拟string函数的实现 浅拷贝 深拷贝 总结 前言 世上有两种耀眼的光芒&#…

Java面向对象案例之描述专业和学生(4)

类的方法图 学生类&#xff1a; 属性&#xff1a;学号&#xff0c;姓名&#xff0c;年龄&#xff0c;所学习的专业方法&#xff1a;学习的方法&#xff0c;描述学习状态。描述内容包括姓名、学号、年龄、所学习的专业信息 专业类&#xff1a; 属性&#xff1a;专业编号&#xf…

2024年【天津市安全员C证】考试资料及天津市安全员C证考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 天津市安全员C证考试资料根据新天津市安全员C证考试大纲要求&#xff0c;安全生产模拟考试一点通将天津市安全员C证模拟考试试题进行汇编&#xff0c;组成一套天津市安全员C证全真模拟考试试题&#xff0c;学员可通过…

链表快慢指针合集(力扣)

876. 链表的中间结点 代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x…