思路
思路一: 一个for loop
- Failed cases: 并没有仔细看清楚题目要求, bigger than neighbors, 如果没有neighbours自然自己是peak啊
- {3}
- {3, 2, 1}
- {1, 2, 3}
思路二: BinarySearch
核心思路是, 如果nums[n - 1] < nums[n] && nums[n] < nums[n + 1] 递增数列 那么后面肯定有peak;同理连续的递减数列. 因此可以用BinarySearch做
- Failed Case: {1}; {1, 2} ; {2, 1}
- peak在头尾的时候, 因为要比较neighboors会有溢出情况. 这是我刚开始的思路, 长长的第一个if条件是为了对付这个的.
- 本来是如下的代码, 想把特殊情况放在主method里面是不对的
public static int findPeakElementByBinarySearch(int[] nums) {
return isPeak(nums, 0, nums.length - 1);
}
private static int isPeak (int[] nums, int start, int end) {
int mid = start + (end - start) / 2;
if ( mid == nums.length - 1 && nums[mid] > nums[mid - 1])
return mid;
else if (nums[mid - 1] < nums[mid] && nums[mid] < nums[mid + 1])
return isPeak(nums, mid + 1, end);
else if (nums[mid - 1] > nums[mid] && nums[mid] > nums[mid + 1])
return isPeak(nums, start, mid - 1);
else return -1;
}
- 这种相邻元素比较的题目中, 特殊情况必须放在binarySearch的method里面, 因为mid的不断变化势必会掉入这种edge conditions
public static int findPeakElementByBinarySearch(int[] nums) {
if (nums.length == 1) return 0;
return isPeak(nums, 0, nums.length - 1);
}
private static int isPeak (int[] nums, int start, int end) {
int mid = start + (end - start) / 2;
if ( mid == nums.length - 1 && nums[mid] > nums[mid - 1]
|| mid == 0 && nums[mid] > nums[mid + 1]
|| nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1])
return mid;
else if (nums[mid - 1] < nums[mid] && nums[mid] < nums[mid + 1])
return isPeak(nums, mid + 1, end);
else if (nums[mid - 1] > nums[mid] && nums[mid] > nums[mid + 1])
return isPeak(nums, start, mid - 1);
else return -1;
}
这个错犯的有点二, 第一个if的三个||相连条件里, 即便加上了start == end这个条件, 也不对. 因为一旦不符合peak, 又会掉落到第三个, 比较前面和后面的, 会出现溢出情况
- 把特殊条件加上, 代码如下
private static int isPeak (int[] nums, int start, int end) {
int mid = start + (end - start) / 2;
if (start == end) return start;
else if (mid == start || mid == end) // end = start + 1
return nums[start] < nums[end] ? end : start;
else if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1])
return mid;
else if (nums[mid - 1] < nums[mid] && nums[mid] < nums[mid + 1])
return isPeak(nums, mid + 1, end);
else if (nums[mid - 1] > nums[mid] && nums[mid] > nums[mid + 1])
return isPeak(nums, start, mid - 1);
else return -1;
}
又出现了一个failed case {2, 1, 2} 并没被考虑到. 其实这种情况左右都是peak, 随便掉入递增递减都可以, 因此可以把最后一个else if变为else, 接收其他条件, 掉入到前面的peak中