문제 링크: https://leetcode.com/problems/find-peak-element/?envType=study-plan-v2&envId=top-interview-150
peak요소: 이웃 요소보다 큰 요소
배열의 peak 인덱스를 반환하자.
nums[i] != nums[i + 1]
성립입력
출력
실행시간이 O(logn)이 되어야 한다는 게 포인트다.
그렇다면 이진탐색 알고리즘이 O(logn) 인데 어떻게 구현할 지 고민되었다.
이런 저런 생각을 하다가, O(n)의 실행 시간을 가지는 코드만 작성할 수 있었다. 너무 시간이 지체되어 다른 풀이를 봤다.
이 풀이는 peak 요소의 좌측은 증가하고 있고, 우측은 감소하고 있다는 peak의 특징을 잘 이용했다.
class Solution {
public int findPeakElement(int[] nums) {
int n = nums.length;
// 길이가 1일 경우
if (nums.length == 1) return 0;
// 가장 왼쪽의 요소가 peak 인지 검사
if (nums[0] > nums[1])
return 0;
// 가장 오른쪽의 요소가 peak 인지 검사
if (nums[n - 1] > nums[n - 2])
return n - 1;
int start = 1, end = n - 2, mid = (start / end) / 2;
while(start <= end) {
mid = (start + end) / 2;
if (nums[mid] > nums[mid-1] && nums[mid] > nums[mid+1])
return mid;
else if (nums[mid] < nums[mid+1])
start = mid+1;
else if (nums[mid] < nums[mid-1])
end = mid-1;
}
return -1;
}
}
이제 다른 문제를 풀 때에도, 정렬을 하지 않아도 이진 탐색을 사용할 수 있다는 사실을 고려해야 한다.
또한 엣지케이스를 if문으로 따로 빼서 처리하는 알고리즘은 사실 깔끔하지 않다고 생각했었다. 따라서 되도록이면, 하나의 로직 안에서 탐색하도록 하려는 편이었는데, 이제는 그런 생각은 하지 말아야겠다.