每日一题局部最小值问题

Posted 唐宋xy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一题局部最小值问题相关的知识,希望对你有一定的参考价值。

局部最小值问题

题目

给定一个无序数组,相邻的数并不相等,那么就会产生很多个局部最小的值,找到任意一个局部最小的值的位置返回

局部最小:一个数满足小于相邻的左边的数和小于相邻的右边的数

例如:arr=[5,2,3,1,4,6,10,9,20], 返回:2或1或9任意一个都可以

解析

  • 关键字:无序数组、相邻的数不相等、找到任意一个局部最小

  • 使用的算法:因为给定的是无序数组,所以看起来不符合前面说到的可以直接使用二分查找算法,但是根据题意,可以将计算的逻辑分为两种情况:

    • 第一种:直接判断第一个数或最后一个数是否小于相邻的数,如果小于,那么直接返回

    • 第二种:如果第一个数和最后一个数都不小于相邻的数,那么数组的趋势如下所示:

      开头和结尾的趋势是下降和上升,那么我们是否在中间的位置找到一个上升或下降的位置,就找到了局部最小。如何快速的找到对应的位置呢?

    • 还是可以使用二分查找法,不过这里只是用二分查找的框架流程,具体的判断条件是单独实现

  • 算法逻辑:

    1. 判断第一个数和最后一个数是否为局部最小的数

    2. 如果不是,那么查看中间的数mid和相邻的数进行比较

      • 如果大于mid-1,那么继续向左边的子数组递归寻找

        因为右边可能是连续上升的一连串数,而左边的子数组是有下降和上升两种不同的趋势,所以必定有局部最小值

      • 如果大于mid+1,那么继续向右边的子数组递归寻找

        因为左边有两个下降,所以可能左边都是连续下降的一连串数,而右边的子数组是有下降以及后面的上升的两种不同的趋势,所以必定是有局部最小值

  • 代码实现

public static int getLessIndex(int[] arr) 
    if(arr == null || arr.length == 0) 
        return -1;
    
    // 判断开头的数是否满足局部最小
    if(arr.length == 1 || arr[0] < arr[1]) 
        return 0;
    
    // 判断结尾的数是否满足局部最小
    if(arr[arr.length - 1] < arr[arr.length - 2]) 
        return arr.length - 1;
    
    // 如果到这里,那么说明0~1是下降的, arr.length-2 ~ arr.length-1是上升的,那么在数组的中间必定有局部最小的数
    // 直接二分查找
    int L = 1;
    int R = arr.length - 2;
    while (L <= R) 
        int mid = L + ((R - L) >> 1);
        if(arr[mid] > arr[mid + 1]) 
   			// 向右边子数组继续找
            L = mid + 1;
         else if(arr[mid] > arr[mid - 1]) 
            // 说明当前的趋势是上升的,因为前两个数是下降的,所以向左边数组寻找
            R = mid - 1;
         else 
            // 因为题目中说明了没有相等的数,说明mid小于左边并且也小于右边,直接返回
            return mid;
        
    
    return -1;

以上是关于每日一题局部最小值问题的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode使数组唯一的最小增量(每日一题)

每日一题1413. 逐步求和得到正数的最小值

每日一题907. 子数组的最小值之和

每日一题907. 子数组的最小值之和

每日一题有序数组判断一个数是否存在

每日一题有序数组判断一个数是否存在