• C++二分算法的应用:寻找峰值原理、源码及测试用例


    二分查找应用:寻找峰值

     说明

    此文是课程https://edu.csdn.net/course/detail/38771 的讲义。

    源码下载:https://download.csdn.net/download/he_zhidan/88458478

     本文涉及的基础知识点

    二分查找算法合集

    题目

    长度为n的数组nums,请返回任意一峰值的索引。符合以下条件之一i便是峰值的索引。

    n等于1

    i等于0

    n>1

    i等于0

    nums[i] >nums[i+1]

    n>1

    i等于n-1

    nums[i] > nums[i-1]

    0

    nums[i]>nums[i-1]

    nums[i]>nums[i+1]

    题目保证nums[i]不等于nums[i+1]。

    2023年11月14整补

    有读者反应看不懂,感谢他的建议,特增补如下。

    定义

    原始数组的连续区域称为子数组。如果一个子数组的首元素在原始数组的索引为i,尾元素在原始数组的索引为j,则用nums[i,j]表示此子数组,也可以用nums[i,j+1)表示。如果nums[i,j]同时符合以下两个条件,则是好子数组。

    一,i为0或nums[i]>nums[i-1]。

    二,j为n-1或nums[j]>nums[j+1]

    推论

    一,如果好子数组nums[i,j]的长度为1,则i就是峰值。

    二,如果好子数组nums[i,j]的长度大于1,则从nums[i,j]找出一个比nums[i,j]短的好子数组nums[i1,j1]。

    三,由于长度不断变短,长度一定会变为1。

    举例

    1 2

    1 2 =>2 (1不是好子数组 2是,长度降为1结束)

    2 1

    2  1 =>2 (2是好子数组 ,1不是,长度降为1结束)

    1 2 3

    1 2 3 => 2 3(1不是好子数组,2 3是)=> 3(3是好数组长度降为1结束)

    3 2 1

    1 2 3 => 3

    1 3 2 

    1 3 2 => 3 2 => 3

    1到4

    1 2 3 4 => 3 4 => 4 

    1 2 4 3 => 4 3 => 4 

    1 3 2 4=> 1 3 => 3

    1 3 4 2 => 4 2 => 4

    1 4 2 3=> 1 4=> 4

    1 4 3 2=> 1 4=> 4

    ...

    2 4 1 3 => 2 4 => 4

    其它

    1 2 3 4 5 6 7 8 => 5 6 7 8 => 7 8 => 8

    9 8 7 6 5 4 3 2 1 => 9 8 7 6 => 9 8 = > 9

    1 3 5 7 9 8 6 4 2 => 9 8 6 4 2 = > 9 8 => 9

    总结

    将好子数组nums[i,j] 分成左右两个子数组nums[i,mid)和nums[mid,j]
    如果nums[mid]> nums[mid-1] 则nums[mid,j]是好子数组
    否则 nums[i,mid)是好子数组

    分析

    假定

    nums[left,r)符合nums[left]>nums[left-1],且nums[r-1]>nums[r]。显然初始情况nums[0,n)符合。

    推论一:如果[left,r)的长度为1,则left就是返回的索引。

    推论二:假定left < mid mid[mid-1],则nums[mid,r)也符合假定。如果mid[mid] < mid[mid-1],则nums[left,mid)也符合假定。

    推论三:推论二也可以也可以理解成分别抛弃[left,mid)和[mid,r)。令mid = left+(r-left)/2,由于r-left>=2,所以left

    时间复杂度

    由于每次抛弃一半,所以需要抛弃logn次。故时间复杂度O(logn)

    核心代码

    class Solution {

    public:

        int findPeakElement(vector& nums) {

            int left = 0, r = nums.size();

            while (r - left > 1)

            {

                const int mid = left + (r - left) / 2;

                if (nums[mid] > nums[mid - 1])

                {

                    left = mid;

                }

                else

                {

                    r = mid;

                }

            }

            return left;

        }

    };

    测试用例

    int main()

    {

        Solution slu;

        vector nums = { 1,2,3,4 };

        int res = slu.findPeakElement(nums);

        assert(3 == res);

        nums = { 4,3,2,1 };

        res = slu.findPeakElement(nums);

        assert(0 == res);

        nums = { 2,5,3,1 };

         res = slu.findPeakElement(nums);

        assert(1 == res);

    }

    https://img-blog.csdnimg.cn/ea2601b3918f4aef836b5fe30da2ebf7.gif#pic_center#pic_center

    其它

    学院课程

    基础算法的C++实现课程,请点击下面的CSDN学院的链接。

    2024年1月15之前完全免费,之后绝大部分免费

    https://edu.csdn.net/course/detail/38771

    C#入职培训

    此课程的目的:让新同事更快完成从学生到C#程序员的转换,更快上手完成C#的开发工作。

    https://edu.csdn.net/course/detail/38768

    C++入职培训

    让新同事更快完成从学生到C++程序员的转换,更快上手完成C++的开发工作。

    https://edu.csdn.net/course/detail/32049

    运行验证环境

    Win10 VS2022 Ck++17 或win7 VS2019 C++17

    每天都补充正能量

    好好学习,天天向上。

    事无终始,无务多业。

    是故置本不安者,无务丰末。

    相关下载

    如果你时间宝贵,只想看精华,请到CSDN下载频道下载《闻缺陷则喜算法册》doc版

    https://download.csdn.net/download/he_zhidan/88348653

    https://img-blog.csdnimg.cn/f95ddae62a4e43a68295601c723f92fb.gif#pic_center

  • 相关阅读:
    JS+Jquery用法
    集线器、交换机、网桥、路由器、网关
    [力扣 Hot100]Day38 翻转二叉树
    【微信小程序】父子组件的创建、通信与事件触发;组件生命周期
    编写一个程序,实现以下功能:(1)计算n个学生的平均成绩aver;(C语言)
    Java高级编程day25【谷】
    C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)
    java授权码方案 软件实现时间授权 离线授权 夏末版
    redis相关文章汇总
    Android学习之路(21) 进程间通信-AIDL与Servce基本使用
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/133975292