当前位置:   article > 正文

LeetCode琅琊榜第十二层-寻找峰值(爬坡算法)_数组 爬坡算法 搜寻峰值

数组 爬坡算法 搜寻峰值

LeetCode162.寻找峰值

难度:中等

博主空间往期力扣

 题目链接


目录

作者原始思路

求最大值法(官方解法一)

题目分析

算法思想

代码实现

代码分析:

官方解法

爬坡算法(方法二)

        算法思想

代码实现

代码分析:

问题;

爬坡算法升级版-二分实现

算法思想

代码实现

代码分析

结论


作者原始思路

求最大值法(官方解法一)

题目分析

  • 1.题目给出:nums[-1] = nums[n] = -∞,所以,我们可以想象数组中是存在这两个元素的,而且这两个元素都是-∞的
  • 2.题目提示中给出nums[i] != nums[i + 1],说明左右两个元素一定不相等

算法思想

  • 1.由于左右两个元素一定不相等,当我们找到最大值的时候,其左右两个元素一定小于这个值,这个值就是我们想要的结果,直接返回其索引即可

代码实现

  1. class Solution {
  2. public int findPeakElement(int[] nums) {
  3. if (nums.length == 1) {
  4. return 0;
  5. }else if (nums.length == 2) {
  6. return nums[0] > nums[1] ? 0 : 1;
  7. }
  8. var max = Integer.MIN_VALUE;
  9. var maxIndex = 0;
  10. for (int i = 0; i < nums.length; i++) {
  11. if (nums[i] > max) {
  12. max = nums[i];
  13. maxIndex = i;
  14. }
  15. }
  16. return maxIndex;
  17. }
  18. // 改进版
  19. public int findPeakElement(int[] nums) {
  20. var maxIndex = -1;
  21. var max = Integer.MIN_VALUE;
  22. for (int i = 0; i < nums.length; i++) {
  23. if (nums[i] > max) {
  24. max = nums[i];
  25. maxIndex = i;
  26. }
  27. }
  28. return maxIndex
  29. }
  30. }

代码分析:

  • 我们通过一次循环找到最大值及其下标,返回其小标即可

官方解法

爬坡算法(方法二)

算法思想

  • 1.假设我们从任意一个位置出发,我们的目的是找到最高峰,所以,我们需要一直往高处走
  • 2.如果发现下一个位置比当前位置大,即比当前位置高,我们就往下一个位置走
  • 3.如果发现上一个位置比当前位置大,我们就往上一个位置走
  • 4.如果发现上一个和下一个位置都比当前的位置小,说明我们到达了高峰,直接返回下标
  • 5.如果发现上一个和下一个位置都比当前位置大,往哪走都可以

代码实现

  1. class Solution {
  2. public int findPeakElement(int[] nums) {
  3. int step = (int) (Math.random() * nums.length);
  4. while (!(compare(nums,step-1,step) < 0 && compare(nums,step,step+1) > 0)) {
  5. if (compare(nums,step,step+1) < 0) {
  6. step++;
  7. }else {
  8. step--;
  9. }
  10. }
  11. return step;
  12. }
  13. public int[] get(int[] nums,int index) {
  14. if (index == nums.length || index == -1) {
  15. return new int[] {0,0};
  16. }
  17. return new int[] {1,nums[index]};
  18. }
  19. public int compare (int[] nums,int index1,int index2) {
  20. var num1 = get(nums,index1);
  21. var num2 = get(nums,index2);
  22. if (num1[0] != num2[0]) {
  23. return num1[0] - num2[0];
  24. }else {
  25. return num1[1] - num2[1];
  26. }
  27. }
  28. }

代码分析:

  • 1.compare()方法
    • 1.1目的:用于比较两个位置的大小,即两个位置的高度,通过比较才可以知道往哪边走
    • 1.2参数:nums(数组,便于访问里面的元素),index1(第一个元素的下标),index2(第二个元素的下标)
    • 1.3get()方法
    • 1.4如果两个数组的第一个元素不相等,说明有一个是-∞,有一个是有数值的,我们直接返回第一个元素之差即可,这样就可以比较大小
    • 1.5如果两个数组的第一个元素相等,我们只需要返回第二个元素之差即可
    • 1.6不懂的话看compareTo源码
  • 2.get()方法
    • 2.1当我们对元素进行比较的时候,对于边界,可能出现-1和nums.length的情况,由于题目中给出了这两个位置是-∞,所以我们要对这连个位置进行处理
    • 2.2参数:nums(数组,便于访问里面的元素),index(所获取元素的下标)
    • 2.3如果发现是特殊的两个位置,我们就返回new int[] {0,0}
    • 2.4否则返回new int[] {1,nums[i]}
      • 注意:0表示特殊情况,1表示普通情况
  • 3.step表示的是站立位置对应的下标,我们可以调用radom方法,获取一个随机位置,随即开始走
  • 4.循环
    • 4.1若发现当前step的位置比左右位置都要大,没必要再去走了,直接结束循环
    • 4.2根据思想完成代码即可,注意:这里其实隐藏了个策略,即如果到了谷底(比两边都小),他会优先向右走

问题;

  • 如果我们仅仅按照上述算法去解决问题的话,最坏时间复杂度下,为O(N)线性阶,不符合题目要求我们完成的对数阶,所以,我们要对算法进行改造升级

爬坡算法升级版-二分实现

算法思想

  • 我们从上面不妨可以看出一个隐藏的细节,即我们爬坡是没有回头路的,即不会往右走完后突然往左走,所以,我们可以引入二分算法
  • 我们假设中间的地方就是我们开始的地方,利用二分的思想找出top,实现对数阶

代码实现

  1. class Solution {
  2. public int findPeakElement(int[] nums) {
  3. var left = 0;
  4. var right = nums.length - 1;
  5. var top = -1;
  6. while (left <= right) {
  7. var mid = (left + right) / 2;
  8. if (compare(nums,mid,mid+1) > 0 && compare(nums,mid,mid-1) > 0) {
  9. top = mid;
  10. break;
  11. }
  12. if (compare(nums,mid,mid+1) < 0) {
  13. left = mid + 1;
  14. }else {
  15. right = mid - 1;
  16. }
  17. }
  18. return top;
  19. }
  20. public int[] get(int[] nums,int index) {
  21. if (index == nums.length || index == -1) {
  22. return new int[] {0,0};
  23. }
  24. return new int[] {1,nums[index]};
  25. }
  26. public int compare (int[] nums,int index1,int index2) {
  27. var num1 = get(nums,index1);
  28. var num2 = get(nums,index2);
  29. if (num1[0] != num2[0]) {
  30. return num1[0] - num2[0];
  31. }else {
  32. return num1[1] - num2[1];
  33. }
  34. }
  35. }

代码分析

  • 1.我们需要动态获取中间mid的索引
  • 2.先判断一下mid对应的元素是否是最高的地方,若是直接赋值给top,并直接退出循环
  • 3.否则,如果mid+1大于mid的话,说明最高的地方一定在mid的右边,所以,在[mid+1,right]的范围内一定有最高点
  • 4.如果mid-1大于mid的话,说明最高的地方一定在mid的左边,所以,在[left,mid-1]的范围内一定有最高点
  • 5.根据以上两种情况对left和right做出更改即可
  • 6.如果不会二分思想可以参考博主的数据结构与算法栏目

结论

        该算法有爬坡和取最大值,更形象的是爬坡算法,但是代码量稍微有点大,取最大值虽有一些抽象,但是比较简单,两个算法都可以,但是比较推荐取最大值,该算法时间消耗的较少

        最后总结必须要掌握的几点

                1.爬坡算法的思想与进阶思想

                        2.取最大值的思想

                                3.代码实现

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/509880
推荐阅读
相关标签
  

闽ICP备14008679号