[LeetCode] 1095. Find in Mountain Array 山形數組中查找目標值



(This problem is an interactive problem.)

You may recall that an array A is a mountain array if and only if:

  • A.length >= 3
  • There exists some i with 0 < i < A.length - 1 such that:
    • A[0] < A[1] < ... A[i-1] < A[i]
    • A[i] > A[i+1] > ... > A[A.length - 1]

Given a mountain array mountainArr, return the minimum index such that mountainArr.get(index) == target.  If such an index doesn't exist, return -1.

You can't access the mountain array directly.  You may only access the array using a MountainArray interface:

  • MountainArray.get(k) returns the element of the array at index k (0-indexed).
  • MountainArray.length() returns the length of the array.

Submissions making more than 100 calls to MountainArray.get will be judged Wrong Answer.  Also, any solutions that attempt to circumvent the judge will result in disqualification.

Example 1:

Input: array = [1,2,3,4,5,3,1], target = 3
Output: 2
Explanation: 3 exists in the array, at index=2 and index=5. Return the minimum index, which is 2.

Example 2:

Input: array = [0,1,2,4,2,1], target = 3
Output: -1
Explanation: 3 does not exist in `the array,` so we return -1.

Constraints:

  • 3 <= mountain_arr.length() <= 10000
  • 0 <= target <= 10^9
  • 0 <= mountain_arr.get(index) <= 10^9

這道題給了一個山形數組 Mountain Array,關於山形數組的題目,之前也出現過,比如 Longest Mountain in ArrayPeak Index in a Mountain Array。所謂的山形數組,就是先上升后下降的數組,注意這里是嚴格的上升和下降。題目中說這個山形數組不能直接訪問元素,而是需要調用 get(),數組的長度需要調用 length(),要求盡可能的少調用這些函數,而且還說了假如調用了超過了 100 次的 get 函數,OJ 會自動判為錯的解法。這完全是斷了直接遍歷一遍數組的這條路啊,畢竟這是一道 Hard 題,要給予足夠的尊重才行。既然不能暴力搜索,更高效的搜索方法可以用二分搜索,但前提條件是數組必須是有序的,這里的數組是先上升再下降的,沒法直接用二分搜索來找目標值。不過假如我們能夠將上升和下降的部分分割開來,就可以分別調用二分搜索法啦,臨界點就是峰值啦。所以首先要用二分法求個峰值,你可能有個疑問,前面不是說了二分法不能在山形數組中查找目標值嗎,怎么這里卻可以用來查找峰值呢?嗯,是個好問題,這其實是個特殊情況,一般來說二分法查找的目標值是固定不變的,而這里查找峰值時不是用一個固定的目標值,而是再求出 mid 后,跟其緊挨的下一個位置比較,假如小於下個位置的值,則說明峰值在后面,此時 left 更新為 mid+1,否則 right 更新為 mid,最后的峰值就保存在 left 中。用類似的方法的題目還有 Find Minimum in Rotated Sorted Array。找到了峰值之后,就可以將數組分為兩段分別進行二分查找了,這里可以寫兩個 while 循環分別查找,也可以放到一個子函數中,不過由於前半段是上升的,后半段是下降的,二者的更新方法正好相反,可以用一個 flag 控制一下。最后假如左半段返回是 -1,則返回右半段的結果即可,參見代碼如下:


class Solution {
public:
    int findInMountainArray(int target, MountainArray &mountainArr) {
        int n = mountainArr.length(), left = 0, right = n - 1, peak = -1;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (mountainArr.get(mid) < mountainArr.get(mid + 1)) left = mid + 1;
            else right = mid;
        }
        peak = left;
        if (mountainArr.get(peak) == target) return peak;
        int idx1 = helper(target, mountainArr, 0, peak - 1, true);
        int idx2 = helper(target, mountainArr, peak + 1, n - 1, false);
        return idx1 == -1 ? idx2 : idx1;
    }
    int helper(int target, MountainArray &mountainArr, int left, int right, bool isAsc) {
        while (left < right) {
            int mid = left + (right - left) / 2, cur = mountainArr.get(mid);
            if (cur == target) return mid;
            else if (cur < target) {
                if (isAsc) left = mid + 1;
                else right = mid;
            } else {
                if (isAsc) right = mid;
                else left = mid + 1;
            }
        }
        return mountainArr.get(right) == target ? right : -1;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1095


類似題目:

Longest Mountain in Array

Peak Index in a Mountain Array

Find Minimum in Rotated Sorted Array

Minimum Number of Removals to Make Mountain Array


參考資料:

https://leetcode.com/problems/find-in-mountain-array/

https://leetcode.com/problems/find-in-mountain-array/discuss/317603/C%2B%2B-Find-Peak-(162)-%2B-Binary-Search

https://leetcode.com/problems/find-in-mountain-array/discuss/317607/JavaC%2B%2BPython-Triple-Binary-Search


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM