πŸ€” λ¬Έμ œ


 

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

 

πŸ˜€ ν’€μ΄


ν•΄λ‹Ή λ¬Έμ œλŠ” 이진 탐색을 쑰금 더 μ‘μš©ν•˜μ—¬ 풀이할 수 μžˆλŠ” λ¬Έμ œμž…λ‹ˆλ‹€. νŠΉμ • 인덱슀λ₯Ό κΈ°μ€€μœΌλ‘œ rotate λ˜μ–΄ κΈ°μ‘΄ λ°©μ‹μœΌλ‘œ 이진 탐색을 ν•˜λŠ” 것이 λΆˆκ°€λŠ₯ν•˜μ—¬ ν•œ 단계 더 과정을 거쳐야 문제 쑰건에 맞게 풀이할 수 μžˆμŠ΅λ‹ˆλ‹€. 

 

κ°€μž₯ 처음 μƒκ°ν•œ 방법은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  1.  rotateκ°€ λͺ‡ 번 λ˜μ—ˆλŠ”μ§€ ν™•μΈν•œλ‹€. 즉, λ°°μ—΄μ—μ„œ κ°€μž₯ μž‘μ€ κ°’μ˜ μœ„μΉ˜λ₯Ό μ°ΎλŠ”λ‹€.
  2. ν•΄λ‹Ή 인덱슀λ₯Ό κΈ°μ€€μœΌλ‘œ 쒌츑과 μš°μΈ‘μ€ μ •λ ¬λ˜μ–΄ μžˆλŠ” μƒνƒœμ΄λ―€λ‘œ 이λ₯Ό λŒ€μƒμœΌλ‘œ 각각 이진탐색을 ν•œλ‹€.
  3. 쒌, 우츑의 이진 νƒμƒ‰μ˜ 결과둜 닡을 κ΅¬ν•œλ‹€.

μœ„ 방법이 μ•„λž˜ 전체 μ½”λ“œμ—μ„œ λ‚˜μ˜¬ 풀이 1에 ν•΄λ‹Ήν•©λ‹ˆλ‹€. μ½”λ“œλ₯Ό λΆ€λΆ„μ μœΌλ‘œ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

# λ°°μ—΄μ—μ„œ κ°€μž₯ μž‘μ€ 값이 μ–΄λ””μžˆλŠ”μ§€ 이진 탐색
def find_smallest_num_index(nums):
    left, right = 0, len(nums) - 1

    while left < right:
        mid = (left + right) // 2
        if nums[mid] > nums[right]:
            left = mid + 1
        else:
            right = mid
    return left

μœ„ μ½”λ“œλ₯Ό 톡해 λ°°μ—΄μ—μ„œ κ°€μž₯ μž‘μ€ κ°’μ˜ 인덱슀λ₯Ό 이진탐색 λ°©μ‹μœΌλ‘œ 찾을 수 있게 되고 μ΄λŠ” 곧 rotateκ°€ λͺ‡ 번 λ˜μ—ˆλŠ”μ§€μ— λŒ€ν•œ 정보λ₯Ό μ€λ‹ˆλ‹€.

 

ν•΄λ‹Ή 인덱슀λ₯Ό κΈ°μ€€μœΌλ‘œ 쒌츑과 μš°μΈ‘μ€ μ •λ ¬λ˜μ–΄μžˆμœΌλ―€λ‘œ 기쑴에 μ•Œκ³  있던 이진 탐색을 μ‚¬μš©ν•  수 있게 λ©λ‹ˆλ‹€. λ”°λΌμ„œ 쒌츑과 우츑 각각 이진 탐색을 톡해 target을 κ²€μƒ‰ν•˜λ©΄ 정닡을 ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ—¬κΈ°κΉŒμ§€κ°€,, κ°€μž₯ 처음 μƒκ°ν–ˆλ˜ 풀이 λ°©λ²•μž…λ‹ˆλ‹€.

 

ν•˜μ§€λ§Œ rotate된 횟수λ₯Ό offset으둜 μ‚¬μš©ν•˜μ—¬ 이진탐색을이진 탐색을 ν•œλ‹€λ©΄ 쒌, 우츑으둜 λ‚˜λˆ„μ–΄ 두 번 이진 탐색을 ν•˜μ§€ μ•Šκ³  ν•œ 번의 μ΄μ§„νƒμƒ‰μœΌλ‘œλ„ 정닡을 ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

ν•΄λ‹Ή λΆ€λΆ„ μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

pivot = find_smallest_num_index(nums)

left, right = 0, len(nums) - 1

while left <= right:
    mid = (left + right) // 2
    mid_with_offset = (mid + pivot) % len(nums)

    if nums[mid_with_offset] == target:
        return mid_with_offset
    elif nums[mid_with_offset] > target:
        right = mid - 1
    else:
        left = mid + 1
return -1

mid_with_offsetμ΄λΌλŠ” mid 값에 pivot 만큼 offset을 μ€€ λ³€μˆ˜λ₯Ό 톡해 마치 배열이 νšŒμ „λ˜κΈ° μ „μ˜ λͺ¨μŠ΅μ„ 가지고 이진 탐색을 ν•˜λŠ” 것과 같은 효과λ₯Ό λ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€! LeetCode 제좜 κ²°κ³Όλ₯Ό 보면 runtime이 반절 κ°€λŸ‰ 쀄어든 λͺ¨μŠ΅μ„ λ³Ό 수 있죠.

 

 


πŸ’» 전체 풀이 μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

풀이1 - 쒌, μš°μΈ‘μ— λŒ€ν•΄ 각각 이진 탐색을 μ μš©ν•˜λŠ” 방식

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

            while left < right:
                mid = (left + right) // 2
                if nums[mid] > nums[right]:
                    left = mid + 1
                else:
                    right = mid
            return left

        def binary_search(arr, _target):
            left, right = 0, len(arr) - 1

            while left <= right:
                mid = (left + right) // 2
                if arr[mid] == _target:
                    return mid
                elif arr[mid] > _target:
                    right = mid - 1
                else:
                    left = mid + 1
            return -1

        smallest_num_index = find_smallest_num_index(nums)


        left_nums = nums[:smallest_num_index]
        right_nums = nums[smallest_num_index:]

        left_idx = binary_search(left_nums, target)
        right_idx = binary_search(right_nums, target)


        if left_idx != -1:
            return left_idx
        if right_idx != -1:
            return right_idx + smallest_num_index
        return -1

풀이2 - Offset을 톡해 이진 탐색을 ν•œ 번만 ν•˜λŠ” μ’€ 더 효율적인 방식

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

            while left < right:
                mid = (left + right) // 2
                if nums[mid] > nums[right]:
                    left = mid + 1
                else:
                    right = mid
            return left

        pivot = find_smallest_num_index(nums)

        left, right = 0, len(nums) - 1

        while left <= right:
            mid = (left + right) // 2
            mid_with_offset = (mid + pivot) % len(nums)

            if nums[mid_with_offset] == target:
                return mid_with_offset
            elif nums[mid_with_offset] > target:
                right = mid - 1
            else:
                left = mid + 1
        return -1

 

λ°˜μ‘ν˜•

'Algorithm > LeetCode' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[LeetCode] 42. Trapping Rain Water - Python  (0) 2022.04.27
[LeetCode] 49. Group Anagrams - Python  (3) 2022.04.26
λ³΅μ‚¬ν–ˆμŠ΅λ‹ˆλ‹€!