題目:
給定數組a, 里面的元素先嚴格遞增后嚴格遞減, 求最大值元素的下標.
分析:
看到這道題目的時候, 我腦海中首先浮現出現的是爬山坡. "先遞增"就是爬坡, "后遞減"就是下坡, 而要找的最大值就是"峰頂". 而"嚴格"二字表明數組中不包含重復數字. OK, 我想最簡單的思路就是, 遍歷一遍, 找到第一個滿足條件a[i]>a[i+1]的元素, 表明開始"下坡", 則i就是所找的最大值下標. 這種解法的時間復雜度為O(n). 當然, 這其中存在兩種情況, 需要單獨拿出來分析一下: 1, 數組單調遞增. 因為題目要求數組"先遞增后遞減", 如果是"單調遞增"的話, 那么最后一個元素, 肯定大於倒數第二個元素. 2, 數組單調遞減. 同第一種情況的分析, "單調遞減"的該數組, 肯定滿足條件a[0]>a[1].
所以, 時間復雜度為O(n)的解法如下:
1 int findPeak(int[] nums) { 2 if (nums != null && nums.length > 0) { 3 if (nums.length == 1) { 4 return 0; 5 } 6 if (nums[0] > nums[1]) {//數組單調遞減 7 return 0; 8 } 9 int index = nums.length-1; 10 if (nums[index] > nums[index-1]) {//數組單調遞增 11 return index; 12 } 13 //循環n-1次 14 for (int i = 0; i < index; i++) { 15 if (nums[i] > nums[i+1]) { 16 return i; 17 } 18 } 19 } 20 return -1; 21 }
OK, 其實, 問題在此已經可以完美解決了. 但是我們就不能更進一步嗎? 為什么不考慮一下時間復雜度為O(logn)的情況呢?
滿足時間復雜度O(logn)的查找算法, 你想到了什么呢? 二分查找. 那么查找的"峰頂"元素會滿足什么樣的條件呢? "峰頂"嘛, 大於左側元素, 也大於右側元素, 即a[i] > a[i-1] && a[i] > a[i+1].
所以, 時間復雜度為O(logn)的解決方法為:
1 int findPeak(int[] nums){ 2 if (nums != null && nums.length > 0) { 3 if (nums.length == 1) { 4 return 0; 5 } 6 if (nums[0] > nums[1]) {//數組單調遞減 7 return 0; 8 } 9 int index = nums.length-1; 10 if (nums[index] > nums[index-1]) {//數組單調遞增 11 return index; 12 } 13 int i = 0, j = index; 14 int mid = 0; 15 while (i < j) {//二分查找 16 mid = (i + j) / 2; 17 if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) { 18 return mid; 19 } else if (nums[mid] > nums[mid + 1]) {//處於下坡段, 即遞減段 20 j = mid - 1; 21 } else if (nums[mid] > nums[mid - 1]) {//處於上坡段, 即遞增段 22 i = mid + 1; 23 } 24 } 25 } 26 return -1; 27 }
PS:
最后, 如果給定數組並不是嚴格先遞增后遞減的, 即其中含有相同的元素, 該怎么辦?
這里只給出引申, 不再給出具體代碼, 大家可以思考一下.