Zero to Hero
article thumbnail
Published 2021. 10. 11. 13:29
33. Search in Rotated Sorted Array Algorithm
 

Search in Rotated Sorted 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

정렬된 임의의 정수로 구성된 list의 특정 index 기준으로 반으로 잘라 만들어진 두 개의 list a, b를 거꾸로 붙인 list가 주어진다.

이 list에서 특정 값이 존재하는지를 판단해 존재한다면 그 인덱스를 반환하고 없다면 -1을 반환한다.

단 시간 복잡도는 log(N)으로 해결한다.

 

예시

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

Input: nums = [1], target = 0
Output: -1

 

1. binary search

from typing import *


class Solution:
    def search(self, nums: List[int], target: int) -> int:
        new_nums = nums + nums
        prev = -float("inf")
        gap = 0
        for index, num in enumerate(new_nums):
            if num < prev:
                gap = index
                break
            prev = num

        start, end = 0, len(nums) - 1
        while start <= end:
            mid = (start + end) // 2

            if new_nums[gap:][mid] >= target:
                end = mid - 1
            else:
                start = mid + 1

        if start >= len(nums) or new_nums[gap:][start] != target:
            return -1
        return (start + gap) % len(nums)

주어진 nums 2개를 이어 붙인 새로운 list를 만들고, 해당 list를 탐색하면서 이전 값 보다 작아지는 위치를 찾아 gap으로 저장한다.

그럼 new_nums [gap:]은 정렬된 배열이기 때문에 이진 탐색을 할 수 있게 되고, start의 nums의 길이 범위를 벗어나거나 가리키는 값이 target이 아닌 경우는 -1을, 그렇지 않다면 start에 gap을 더한 값의 모듈로 연산을 한 인덱스 값을 반환한다.

 

이건 지수 시간 복잡도가 아니다. 왜냐하면 이진 탐색 전에 선형 탐색을 들어가기 때문에...

예를 들어 nums = [1,3,5] 면 new_nums = [1,3,5,1,3,5] 이기 때문에 O(N)을 반드시 소모한다.

 

2. 최적화

from typing import *


class Solution:
    def search(self, nums: List[int], target: int) -> int:
        start, end = 0, len(nums) - 1

        while start < end:
            mid = (start + end) // 2

            if nums[mid] <= nums[end]:
                end = mid
            else:
                start = mid + 1
        gap = start
        print(gap)
        start, end = 0, len(nums) - 1

        while start <= end:

            mid = (start + end) // 2
            r_mid = (mid + gap) % len(nums)
            if nums[r_mid] == target:
                return r_mid
            elif nums[r_mid] > target:
                end = mid - 1
            else:
                start = mid + 1

        return -1

두 번의 이진 탐색을 사용한다. 그렇게 되면 O(logN) + O(logN) 이기 때문에 O(logN)의 시간 복잡도를 가진다.

첫 번째 이진 탐색은 최적 값을 찾는다. 선형 탐색이 아니라 mid가 end가 가리키는 값보다 크면 start를 (mid+1)로 전진시키고, 그 반대라면 end를 mid로 옮겨서 gap을 찾는다.

 

gap을 찾았으니 다시 이진 탐색으로 target이 존재하는지 찾는다. 여기서 mid와 r_mid가 있는데 mid는 실제 이진 탐색을 하게 되는 중간 인덱스이고, r_mid는 mid+gap에 모듈로 연산을 한 값이다. 이런 식으로 정렬된 list를 쪼개서 뒤집어 붙인 경우에는 시작 인덱스의 위치인 gap만 찾으면 위와 같은 방법으로 이진 탐색을 할 수 있다. 

 

3. 이해 못 함

 

The -INF and INF method but with a better explanation for dummies like me - LeetCode Discuss

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

이 방법은 이해 못했다.

 

예나 지금이나 인덱스 조작해서 하는 문제는 굉장히 못 푸는 것 같다.

2번 풀이도 첫 번째 이진 탐색의 인덱스 설정하는 부분 때문에 거의 한 시간은 잡아먹었다. 계속 쓰다 보니깐 그냥 인덱스 조정하는 법을 암기해버렸는데 암기하면 어차피 나중에 못 써먹는다.

'Algorithm' 카테고리의 다른 글

986. Interval List Intersections  (0) 2021.10.14
74. Search a 2D Matrix  (0) 2021.10.11
34. Find First and Last Position of Element in Sorted Array  (0) 2021.10.11
타겟 넘버  (0) 2021.10.07
2477번: 참외밭  (0) 2021.10.05
profile

Zero to Hero

@Doljae

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!