C++ 二分查找算法:山脉数组中查找目标值

简介: C++ 二分查找算法:山脉数组中查找目标值

本文涉及的基础知识点

二分查找算法合集

题目

给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。

如果不存在这样的下标 index,就请返回 -1。

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:

首先,A.length >= 3

其次,在 0 < i < A.length - 1 条件下,存在 i 使得:

A[0] < A[1] < … A[i-1] < A[i]

A[i] > A[i+1] > … > A[A.length - 1]

你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据

MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)

MountainArray.length() - 会返回该数组的长度

分析

分三步。

寻找最后一个nums[mid-1]<nums[mid]的mid,当长度大于等于2是,mid-1是左子数组最后一个元素,mid是右子数组第一个元素,两个子数组都不为空,所以索引不会非法。
升序中寻找目标数,不一定存在
降序中寻找目标值,不一定存在

代码

核心代码

class Solution {
public:
int findInMountainArray(int target, MountainArray& mountainArr) {
int iTopIndex = TopIndex(mountainArr);
//左边找
{
int left = 0, right = iTopIndex;//左开右闭
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
const int midValue = mountainArr.get(mid);
if (midValue == target)
{
return mid;
}
else if (midValue < target)
{
left = mid;
}
else
{
right = mid;
}
}
if( mountainArr.get(left) == target)
{
return left;
}
}
{//右边找
int left = iTopIndex, right = mountainArr.length();//左开右闭
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
std::cout << mid << " ";
const int midValue = mountainArr.get(mid);
if (midValue == target)
{
return mid;
}
else if (midValue < target)
{
right = mid;
}
else
{
left = mid;
}
}
if( mountainArr.get(left) == target)
{
return left;
}
return -1;
}
return iTopIndex;
}
int TopIndex( MountainArray& mountainArr)
{
int left = 0, right = mountainArr.length();
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
if (mountainArr.get(mid - 1) < mountainArr.get(mid))
{
left = mid;
}
else
{
right = mid;
}
}
return left;
}
};

小幅优化后的代码

左半边寻找,可以理解为:寻找最后一个<=

右半边寻找,可以理解为:寻找最后一个>=

class Solution {
public:
int findInMountainArray(int target, MountainArray& mountainArr) {
int iTopIndex = TopIndex(mountainArr);
//左边找
{
int left = 0, right = iTopIndex;//左开右闭
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
const int midValue = mountainArr.get(mid);
if (midValue <= target)
{
left = mid;
}
else
{
right = mid;
}
}
if (mountainArr.get(left) == target)
{
return left;
}
}
{//右边找
int left = iTopIndex, right = mountainArr.length();//左开右闭
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
std::cout << mid << " ";
const int midValue = mountainArr.get(mid);
if (midValue >= target)
{
left = mid;
}
else
{
right = mid;
}
}
if (mountainArr.get(left) == target)
{
return left;
}
return -1;
}
return iTopIndex;
}
int TopIndex(MountainArray& mountainArr)
{
int left = 0, right = mountainArr.length();
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
if (mountainArr.get(mid - 1) < mountainArr.get(mid))
{
left = mid;
}
else
{
right = mid;
}
}
return left;
}
};

2022年12月旧代码

class Solution {
public:
int findInMountainArray(int target, MountainArray &mountainArr) {
int iMaxK = FindMax(mountainArr,0, mountainArr.length());
int iLeft = FindLeft(mountainArr, 0, iMaxK + 1, target);
if (-1 != iLeft)
{
return iLeft;
}
return FindRight(mountainArr, iMaxK, mountainArr.length(), target);
}
int FindMax( MountainArray &mountainArr, int iMin, int iMax)
{
if (iMax - iMin <= 1)
{
return iMin;
}
int iMid = (iMin + iMax) / 2;
if (mountainArr.get(iMid - 1) < mountainArr.get(iMid))
{
return FindMax(mountainArr, iMid, iMax);
}
return FindMax(mountainArr, iMin, iMid);
}
int FindLeft(MountainArray &mountainArr, int iMin, int iMax, int target)
{
if (iMax - iMin <= 1)
{
if (mountainArr.get(iMin) == target)
{
return iMin;
}
return -1;
}
int iMid = (iMin + iMax) / 2;
const int iMidValue = mountainArr.get(iMid);
if (iMidValue == target)
{
return iMid;
}
if (iMidValue < target)
{
return FindLeft(mountainArr, iMid, iMax,target);
}
return FindLeft(mountainArr, iMin, iMid, target);
}
int FindRight(MountainArray &mountainArr, int iMin, int iMax, int target)
{
if (iMax - iMin <= 1)
{
if (mountainArr.get(iMin) == target)
{
return iMin;
}
return -1;
}
int iMid = (iMin + iMax) / 2;
const int iMidValue = mountainArr.get(iMid);
if (iMidValue == target)
{
return iMid;
}
if (iMidValue < target)
{
return FindLeft(mountainArr, iMin, iMid, target);
}
return FindLeft(mountainArr, iMid, iMax, target);
}
};
相关文章
|
2天前
|
C++
C++语言如何利用函数来处理数组
C++语言如何利用函数来处理数组
|
4天前
|
算法 数据处理 C++
C++一分钟之-迭代器与算法
【6月更文挑战第21天】C++ STL的迭代器统一了容器元素访问,分为多种类型,如输入、输出、前向、双向和随机访问。迭代器使用时需留意失效和类型匹配。STL算法如查找、排序、复制要求特定类型的迭代器,注意容器兼容性和返回值处理。适配器和算法组合增强灵活性,但过度使用可能降低代码可读性。掌握迭代器和算法能提升编程效率和代码质量。
22 3
|
9天前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
33 10
|
2天前
|
存储 安全 算法
C++的内置数组和STL array、STL vector
C++的内置数组和STL array、STL vector
|
4天前
|
机器学习/深度学习 算法 索引
数据结构算法--1 顺序查找二分查找
**顺序查找时间复杂度为O(n)**,适合无序列表,可以通过`enumerate`或直接遍历索引来实现。**二分查找时间复杂度为O(logn)**,适用于有序列表,利用Python中`left`、`right`指针和`mid`点不断缩小搜索范围。效率上二分查找更优。
|
4天前
|
存储 算法 Java
Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。
【6月更文挑战第21天】Java查找算法概览:二分查找适用于有序数组,通过比较中间元素缩小搜索范围;哈希查找利用哈希函数快速定位,示例中使用HashMap存储键值对,支持多值关联。简单哈希表实现未涵盖冲突解决和删除操作。
13 1
|
6天前
|
存储 算法 安全
C++一分钟之-数组与指针基础
【6月更文挑战第19天】在C++中,数组和指针是核心概念,数组是连续内存存储相同类型的数据,而指针是存储内存地址的变量。数组名等同于指向其首元素的常量指针。常见问题包括数组越界、尝试改变固定大小数组、不正确的指针算术以及忘记释放动态内存。使用动态分配和智能指针可避免这些问题。示例代码展示了安全访问和管理内存的方法,强调了实践的重要性。
24 3
|
1天前
|
算法
算法入门——二分查找
算法入门——二分查找
4 0
|
1天前
|
算法 前端开发 安全
C++算法模板
C++算法模板
3 0
|
5天前
|
算法 搜索推荐 Python
算法===二分查找
算法===二分查找