A peak element is an element that is greater than its neighbors.html
Given an input array nums
, where nums[i] ≠ nums[i+1]
, find a peak element and return its index.數組
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.post
You may imagine that nums[-1] = nums[n] = -∞
.優化
Example 1:url
Input: nums = Output: 2 Explanation: 3 is a peak element and your function should return the index number 2.[1,2,3,1]
Example 2:spa
Input: nums = 1,2,1,3,5,6,4] Output: 1 or 5 Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6. [
Note:code
Your solution should be in logarithmic complexity.htm
這道題是求數組的一個峯值,若是這裏用遍歷整個數組找最大值確定會出現Time Limit Exceeded,但題目中說了這個峯值能夠是局部的最大值,因此咱們只須要找到第一個局部峯值就能夠了。所謂峯值就是比周圍兩個數字都大的數字,那麼只須要跟周圍兩個數字比較就能夠了。既然要跟左右的數字比較,就得考慮越界的問題,題目中給了nums[-1] = nums[n] = -∞,那麼咱們其實能夠把這兩個整型最小值直接加入到數組中,而後從第二個數字遍歷到倒數第二個數字,這樣就不會存在越界的可能了。因爲題目中說了峯值必定存在,那麼有一個很重要的corner case咱們要注意,就是當原數組中只有一個數字,且是整型最小值的時候,咱們若是還要首尾墊數字,就會造成一條水平線,從而沒有峯值了,因此咱們對於數組中只有一個數字的狀況在開頭直接判斷一下便可,參見代碼以下:blog
C++ 解法一:ip
class Solution { public: int findPeakElement(vector<int>& nums) { if (nums.size() == 1) return 0; nums.insert(nums.begin(), INT_MIN); nums.push_back(INT_MIN); for (int i = 1; i < (int)nums.size() - 1; ++i) { if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) return i - 1; } return -1; } };
Java 解法一:
class Solution { public int findPeakElement(int[] nums) { if (nums.length == 1) return 0; int[] newNums = new int[nums.length + 2]; System.arraycopy(nums, 0, newNums, 1, nums.length); newNums[0] = Integer.MIN_VALUE; newNums[newNums.length - 1] = Integer.MIN_VALUE; for (int i = 1; i < newNums.length - 1; ++i) { if (newNums[i] > newNums[i - 1] && newNums[i] > newNums[i + 1]) return i - 1; } return -1; } }
咱們能夠對上面的線性掃描的方法進行一些優化,能夠省去首尾墊值的步驟。因爲題目中說明了局部峯值必定存在,那麼實際上能夠從第二個數字開始日後遍歷,若是第二個數字比第一個數字小,說明此時第一個數字就是一個局部峯值;不然就日後繼續遍歷,如今是個遞增趨勢,若是此時某個數字小於前面那個數字,說明前面數字就是一個局部峯值,返回位置便可。若是循環結束了,說明原數組是個遞增數組,返回最後一個位置便可,參見代碼以下:
C++ 解法二:
class Solution { public: int findPeakElement(vector<int>& nums) { for (int i = 1; i < nums.size(); ++i) { if (nums[i] < nums[i - 1]) return i - 1; } return nums.size() - 1; } };
Java 解法二:
public class Solution { public int findPeakElement(int[] nums) { for (int i = 1; i < nums.length; ++i) { if (nums[i] < nums[i - 1]) return i - 1; } return nums.length - 1; } }
因爲題目中提示了要用對數級的時間複雜度,那麼咱們就要考慮使用相似於二分查找法來縮短期,因爲只是須要找到任意一個峯值,那麼咱們在肯定二分查找折半後中間那個元素後,和緊跟的那個元素比較下大小,若是大於,則說明峯值在前面,若是小於則在後面。這樣就能夠找到一個峯值了,代碼以下:
C++ 解法三:
class Solution { public: int findPeakElement(vector<int>& nums) { int left = 0, right = nums.size() - 1; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] < nums[mid + 1]) left = mid + 1; else right = mid; } return right; } };
Java 解法三:
public class Solution { public int findPeakElement(int[] nums) { int left = 0, right = nums.length - 1; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] < nums[mid + 1]) left = mid + 1; else right = mid; } return right; } }
相似題目:
Peak Index in a Mountain Array
參考資料:
https://leetcode.com/problems/find-peak-element