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

算法每日双题精讲 —— 二分查找(山脉数组的峰顶索引,寻找峰值)

 🌟快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 🌟 

别再犹豫了!快来订阅我们的算法每日双题精讲专栏,一起踏上算法学习的精彩之旅吧💪   


        在算法的广袤世界里,二分查找算法凭借其高效性与独特的解题思路,成为众多开发者和算法爱好者的得力工具。今天,让我们一同深入研究 “山脉数组的峰顶索引” 以及 “寻找峰值” 这两道经典题目,探索二分查找算法在其中的巧妙应用。

目录

一、山脉数组的峰顶索引

📖题目描述

🧠讲解算法原理

💻代码实现(以C++为例)

复杂度分析

二、寻找峰值

📖题目描述

🧠讲解算法原理

💻代码实现(以 C++ 为例)

复杂度分析


一、山脉数组的峰顶索引

题目链接👉【力扣】

📖题目描述

 

🧠讲解算法原理

        对于这道题,我们可以利用二分查找的思想来高效地找到山脉数组的峰顶索引。

首先,初始化左指针 left 为 1,右指针 right 为数组长度减 2。这是因为数组两端的元素不可能是峰顶(根据山脉数组的定义)。

在循环过程中,计算中间索引 mid = left + (right - left) / 2。然后比较 arr[mid] 与 arr[mid + 1] 的大小关系:

  • 如果 arr[mid] < arr[mid + 1],说明当前位置在上升坡,峰顶在 mid 的右侧,所以将 left 更新为 mid + 1
  • 如果 arr[mid] > arr[mid + 1],说明当前位置在下降坡或者已经是峰顶,峰顶在 mid 及其左侧,将 right 更新为 mid

当 left 等于 right 时,循环结束,此时 left(或 right)所指向的索引就是山脉数组的峰顶索引。

💻代码实现(以C++为例)

#include <iostream>
#include <vector>

using namespace std;

// 寻找山脉数组的峰顶索引
int peakIndexInMountainArray(vector<int>& arr) {
    int left = 1, right = arr.size() - 2;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] < arr[mid + 1]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return left;
}

int main() {
    vector<int> arr = {0, 1, 0};
    int result = peakIndexInMountainArray(arr);
    cout << "山脉数组的峰顶索引是: " << result << endl;
    return 0;
}

复杂度分析

  • 时间复杂度:每次循环都将搜索区间缩小一半,所以时间复杂度为 O(logn),其中  是数组的长度。相比从数组头部到尾部逐个遍历查找峰顶的暴力解法(时间复杂度为O(n) ),效率有显著提升。
  • 空间复杂度:整个过程只使用了几个额外的变量来存储指针和中间索引,不需要额外的复杂数据结构,空间复杂度为O(1) ,在空间利用上非常高效。

二、寻找峰值

题目链接👉【力扣】

📖题目描述

🧠讲解算法原理

        这道题同样可以借助二分查找来解决。

初始化左指针 left 为 0,右指针 right 为数组长度减 1。

在循环中,计算中间索引 mid = left + (right - left) // 2。接着比较 nums[mid] 与 nums[mid + 1] 的大小:

  • 若 nums[mid] < nums[mid + 1],说明峰值在 mid 的右侧,将 left 更新为 mid + 1
  • 若 nums[mid] > nums[mid + 1],说明峰值在 mid 及其左侧,将 right 更新为 mid

当 left 等于 right 时,循环结束,此时返回的 left(或 right)就是一个峰值的索引。因为根据假设,数组两端虚拟的负无穷保证了一定能找到峰值。

💻代码实现(以 C++ 为例)

#include <iostream>
#include <vector>

using namespace std;

// 寻找峰值元素的索引
int findPeakElement(vector<int>& nums) {
    int left = 0, right = nums.size() - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < nums[mid + 1]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return left;
}

int main() {
    vector<int> nums = {1, 2, 3, 1};
    int result = findPeakElement(nums);
    cout << "一个峰值元素的索引是: " << result << endl;
    return 0;
}

复杂度分析

  • 时间复杂度:由于每次迭代都能将搜索区间缩小一半,时间复杂度为 O(logn),其中 n 是数组的长度。这种方式比遍历整个数组查找峰值(时间复杂度为 )要快得多。
  • 空间复杂度:仅使用了几个简单的变量来存储指针和中间索引,没有使用额外的复杂数据结构,空间复杂度为 O(1),在空间上非常节省。

        通过对这两道题目的深入分析,我们进一步体会到二分查找算法的强大之处。在实际的算法学习和编程过程中,灵活运用二分查找及其变体,能够大大提高解决问题的效率。希望大家继续努力,不断探索算法世界的奥秘!我会持续为大家带来更多精彩的算法知识分享。

 

 


http://www.kler.cn/a/519667.html

相关文章:

  • windows蓝牙驱动开发-生成和发送蓝牙请求块 (BRB)
  • 996引擎 - 前期准备-配置开发环境
  • 每日一题 427. 建立四叉树
  • 专为课堂打造:宏碁推出三款全新耐用型 Chromebook
  • Unity——从共享文件夹拉取资源到本地
  • 苍穹外卖-day10
  • 使用 MySQL JSON 查询筛选嵌套字段的值
  • IMX6ull项目环境配置
  • [ACTF2020 新生赛]Include1
  • 服务器中热备份和冷备份的区别
  • Debian或Ubuntu系统中重置MySQL的root密码
  • 【2024年华为OD机试】 (C卷,200分)- 贪吃的猴子(JavaScriptJava PythonC/C++)
  • Solon Cloud Gateway 开发:熟悉 Completable 响应式接口
  • 【力扣Hot 100】矩阵2
  • Avalonia+ReactiveUI跨平台路由:打造丝滑UI交互的奇幻冒险
  • 文献阅读记录8--Enhanced Machine Learning Sketches for Network Measurements
  • UE4通过反射获取蓝图或子类属性值
  • PAT甲级-1023 Have Fun with Numbers
  • JVM常见知识点
  • IOS 自定义代理协议Delegate
  • 页高速缓存与缓冲区缓存的应用差异
  • YOLOv9改进,YOLOv9检测头融合ASFF(自适应空间特征融合),全网首发
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.1 从零搭建NumPy环境:安装指南与初体验
  • 【Docker】ubuntu中 Docker的使用
  • 面向长文本的多模型协作摘要架构:多LLM文本摘要方法
  • MyBatis框架基础学习(1)