코딩 테스트 및 알고리즘/leetcode for google

leetcode medium : Peak Index in a Mountain Array

띠리링구 2022. 12. 16. 08:54

https://leetcode.com/problems/peak-index-in-a-mountain-array/description/

 

Peak Index in a Mountain Array - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

Peak Index in a Mountain Array

풀기 전

예전에 비슷한 문제를 풀었던거같다. 그때는 mountain array인지 아닌지 검사하는거라서 linear time으로 풀었던거 같은데, 이번엔 조건이 살짝 달라졌다.

  • 일부 정렬되어 있는 array
  • O(log N) time complexity
  • 주어진 array는 무조건 mountain array

누가 봐도 binary search를 하라고 대놓고 말해주고 있는거같다.

인덱스를 low와 high로 잡아놓고 mid인덱스에서 list[mid-1] < list[mid] > list[mid+1]을 만족하는지 검사하면 될거같다. 만약 list[mid-1] < list[mid] < list[mid+1]이라면 mid가 더 오른쪽에 있는 것이므로 low를 높여주면 되겠고 그 반대라면 high을 낮춰주면 되겠다.

코드 설명

class Solution:
    def peakIndexInMountainArray(self, arr: List[int]) -> int:
        low = 1
        high = len(arr) - 2

        while low <= high:
            mid = (low + high) // 2

            if arr[mid-1] < arr[mid] > arr[mid+1]:
                return mid
            if arr[mid-1] < arr[mid] < arr[mid+1]:
                low = mid + 1
            else:
                high = mid

        return -1

직접 돌려보지 않으면서 off by one 버그 없이 어떻게 풀지 고민했다.

시뮬레이션을 직접 돌려보면서 검증했고 한 번에 통과했다.

low = 1
high = len(arr) - 2

일단 array의 길이가 최소 3 이상이고 peak는 무조건 중간에 있어야 하므로 peak index의 하한선은 1, 상한선은 len(arr) - 2다.

while low <= high:

수많은 binary search 구현 경험 결과 while 조건에서는 equal 조건도 포함시키는게 좋다.

equal 없이 low < high로만 되어있으면 low = high인 경우에 mid가 정답인지 아닌지 어떻게 검증할 것인가?

mid = (low + high) // 2

if arr[mid-1] < arr[mid] > arr[mid+1]:
    return mid

mid를 구하고 나서 가장 먼저 해야 될 것은 정답 조건을 검사하는 것이다.

정답이 맞으면 mid를 반환한다.

if arr[mid-1] < arr[mid] < arr[mid+1]:
    low = mid + 1
else:
    high = mid

무한루프를 방지하기 위해 한쪽에선 값을 올려주고(mid+1)

한쪽에선 값을 똑같게 만들어준다 (high = mid)

이렇게 하면 while문 안에서 정답이 무조건 걸리게 된다.

return -1

정답을 못찾으면 -1을 리턴한다. 하지만 인풋 array가 무조건 mountain array이기 때문에 이 리턴문까지 실행되는 경우는 없다.

분석 및 피드백

Time Complexity는 O(log N)

Space Complexity는 O(1)

99%, 95%

코드도 지저분하지 않은 것 같고 특별히 손볼곳은 없어보인다.

하지만 항상 binary search를 어떻게 하면 버그 없이 깔끔하게 구현할 수 있을까는 고민이 된다.

솔루션 학습

Binary Search 말고도 Golden Section Search라는 알고리즘이 있다는 걸 알게됐다. 효율성에 대해서는 논란이 좀 있어서 binary search보다 무조건 낫다고 단정짓긴 힘들거같다. 로그타임인건 확실.

def peakIndexInMountainArray(self, A):
    def gold1(l, r):
        return l + int(round((r - l) * 0.382))

    def gold2(l, r):
        return l + int(round((r - l) * 0.618))
    l, r = 0, len(A) - 1
    x1, x2 = gold1(l, r), gold2(l, r)
    while x1 < x2:
        if A[x1] < A[x2]:
            l = x1
            x1 = x2
            x2 = gold1(x1, r)
        else:
            r = x2
            x2 = x1
            x1 = gold2(l, x2)
    return A.index(max(A[l:r + 1]), l)

binary search 3분의 1 버전인거같기도 하고.. 잘 모르겠다.