Leetcode 33. Search in Rotated Array [lowerbound와 upperbound]
문제
Search in Rotated Sorted Array - LeetCode
내 풀이
class Solution {
public int lowerBound(int[] nums, int target) {
int lo = 0;
int hi = nums.length-1;
while(lo<hi) {
int mid = (lo+hi)/2;
if(nums[mid] > target) {
lo = mid+1;
}else {
hi = mid;
}
}
return lo;
}
public int search(int[] nums, int target) {
int n = nums.length;
// nums 배열에서 최소값 위치 찾기
int rot = lowerBound(nums, nums[n-1]);
boolean flag = false;
// target 찾기
int lo = rot;
int hi = n-1;
int rst = 0;
while(lo <= hi) {
int mid = (lo+hi)/2;
if(nums[mid]==target) {
flag = true;
rst = mid;
break;
}else if(nums[mid] > target) {
hi = mid-1;
}else {
lo = mid+1;
}
}
if(flag) return rst;
lo = 0;
hi = rot-1;
rst = 0;
while(lo <= hi) {
int mid = (lo+hi)/2;
if(nums[mid]==target) {
flag = true;
rst = mid;
break;
}else if(nums[mid] > target) {
hi = mid-1;
}else {
lo = mid+1;
}
}
if(flag) return rst;
return -1;
}
}
해설
def search(nums: List[int], target: int) -> int:
# pivot 찾기 : 최솟값을 찾는 binary search
def find_pivot(nums):
lt, rt = 0, len(nums)-1
while lt < rt:
mid = (lt+rt)//2
if nums[mid] > nums[rt]:
lt = mid+1
else:
rt = mid
return lt
pivot = find_pivot(nums)
# 피벗 기준 이진검색
n = len(nums)
lt, rt = 0, n-1
while lt<=rt:
mid = (lt+rt)//2
real_mid = (mid+pivot)%n # 중앙의 위치 mid에서 pivot만큼 이동하고, 배열의 길이를 초과할 경우 %로 회전될 수 있도록 처리
# 타켓과 값을 비교하는 부분은 mid가 아닌 mid_pivot을 기준으로 하되, left와 right는 mid를 기준으로 이동한다.
if nums[real_mid] < target:
lt = mid+1
elif nums[real_mid] > target:
rt = mid-1
else:
return real_mid
return -1
pivot = find_pivot(nums,0,len(nums)-1)
print(pivot)
return pivot
lowerbound와 upperbound. (+ lowerbound를 이용하여 rotated array에서 최솟값 위치 찾기)
'''
lowerbound
: (배열에 같은 원소가 여러 개 있을 경우) 찾고자 하는 값 이상이 처음 나타나는 위치
[문제 예시]
n개로 이루어진 정수 집합에서 k 이상인 수가 처음으로 등장하는 위치를 찾으시오.
단, 입력되는 집합은 오름차순으로 정렬되어 있으며 (이분탐색 가능), 같은 수가 여러 개 존재할 수 있다.
'''
import bisect
def lowerbound(arr, key):
# arr은 정렬되어있다고 가정
lo, hi = 0, len(arr)-1
while lo<hi:
mid = (lo+hi)//2
if arr[mid] < key:
lo = mid+1
else:
hi = mid
# while이 끝날때까지 돈다. 도중에 key랑 같으면 return 같은거 안함. -> 당연
return lo
def upperbound(arr, key):
lo, hi = 0, len(arr)
lo, hi = 0, len(arr) - 1
while lo < hi:
mid = (lo + hi) // 2
if arr[mid] <= key: # 여기만 달라짐
lo = mid + 1
else:
hi = mid
return lo
arr = [1,2,3,3,4,4,4,5,6,7,8]
key = 4 # 3과 같거나 큰 수가 나오는 첫 위치가 lowerbound이다.
print(lowerbound(arr, key))
print(upperbound(arr, key))
# bisect 모듈 사용
print(bisect.bisect_left(arr, 4)) # lowerbound
print(bisect.bisect_right(arr, 4)) # upperbound
응용 : 아래와 같은 배열에서 최솟값 이상이 처음으로 등장하는 위치를 구해라 O(logN) -> (lowerbound를 이용)
def find_min_loc(arr):
lo, hi = 0, len(arr)-1
while lo < hi:
mid = (lo+hi)//2
if arr[mid] > arr[hi]: # 왜?? < 이게 아니지?? => 직접 그려보기
lo = mid+1
else:
hi = mid
return lo
arr = [5,6,7,8,1,2,3,4]
print(find_min_loc(arr))