山脉数组(二分法的应用)

本人算法太不简洁了,所以参照了甜姨的算法,不好意思是照抄。。。。。欢迎关注公众号甜姨的奇妙冒险(宣传一波为敬吧)
我在此代码上就添加了一下自己的想法
题目如下
山脉数组(二分法的应用)_第1张图片
山脉数组(二分法的应用)_第2张图片
以下就是我对这道题的想法了,解题的关键是在于理解山脉数组的性质和二分查找的应用。
山脉数组就是中间有一个点是最大值,山脉数组往左是递减,往右是递增,那么求所求target出现的位置和次数就应该在峰点的左右分别应用二分查找;
关键点有两个:
1.求解山脉数组峰值的位置;
2.分别在峰值左边和峰值右边应用二分查找相应结点
然后就是分情况,所查结点target有四种情况
(1) 在左边数组存在,但在右边不存在;
(2) 在右边存在,但在左边不存在;
(3) 在左边和右边都存在;
(4) 在左边和右边都不存在;
因为左边数组的索引值一定是小于右边数组的,所以对于(1)(3)返回的索引值一定是左边数组的,所以左边的数组优先进行二分查找。

class Solution {
    public int findInMountainArray(int target, MountainArray mountainArr) {
        // 先找到峰顶索引 peakIdx
        int lo = 0, hi = mountainArr.length() - 1;
        while (lo + 1 < hi) {
            int mid = lo + (hi - lo) / 2;
            int midVal = mountainArr.get(mid);
            
            if (midVal > mountainArr.get(mid - 1)) {//如果左边的数小于峰值,证明峰值可能还在其右边
                lo = mid;
            } else {
                hi = mid;
            } 
        }//结束的时候lo + 1= hi
        int peakIdx = mountainArr.get(lo) > mountainArr.get(hi)? lo: hi;//lo和high中由一个是峰值

        
        // 根据峰顶将山脉数组分为「升序数组」和「降序数组」两段,分别进行二分查找
        int idx = binSearch(mountainArr, 0, peakIdx, target, true);//优先进行左边数组的二分查找
        return idx != -1? idx: binSearch(mountainArr, peakIdx + 1, mountainArr.length() - 1, target, false);
    }

    private int binSearch(MountainArray mountainArr, int lo, int hi, int target, boolean asc) {//asc控制是否是升序***好方法
        while (lo <= hi) {
            int mid = lo + (hi - lo) / 2;
            int midVal = mountainArr.get(mid);
            
            if (midVal == target) {
                return mid;
            }
            if (midVal < target) {
                lo = asc? mid + 1: lo;
                hi = asc? hi: mid - 1;
            } else {
                hi = asc? mid - 1: hi;
                lo = asc? lo: mid + 1;
            }
        }
        return -1;
    }
}

当然,查找峰值也可以用A[i],i++;
当A[i+1]

你可能感兴趣的:(LeetCode,数据结构)