오름차순(비내림차순)으로 정렬된 배열 nums와 하나의 숫자 target이 주어졌을 때, 이 타깃이 해당 배열의 과반수(majority) 요소인지 판별해야 합니다.
여기서 과반수 요소란 길이가 N인 배열에서 N/2번보다 많이 등장하는 요소를 의미합니다. 예를 들어 배열이 [2, 4, 5, 5, 5, 5, 5, 6, 6]이고 타깃이 5라면, 5는 총 5번 등장하므로 배열 길이 9의 절반인 4.5보다 큽니다. 따라서 결과는 true가 됩니다.
문제 해결 접근 방법
정렬된 배열의 특성을 활용하면 이진 탐색(binary search)으로 효율적으로 해결할 수 있습니다. 핵심 아이디어는 타깃 값이 처음 나타나는 위치와 마지막으로 나타나는 위치를 찾아 그 개수를 계산하는 것입니다.
이를 위해 두 개의 보조 함수를 사용합니다.
1. lower() 함수 — 첫 번째 등장 위치 찾기
- 배열
arr과target두 개의 인자를 받습니다. low := 0,high := len(arr)로 초기화합니다.low < high인 동안 반복합니다.mid := low + (high - low) // 2arr[mid] == target이면high = mid, 아니면low = mid + 1
arr[high] == target이면high를 반환하고, 아니면 -1을 반환합니다.
2. upper() 함수 — 마지막 등장 위치 찾기
- 마찬가지로 배열
arr과target을 인자로 받습니다. low = 0,high = len(arr) - 1로 초기화합니다.low < high인 동안 반복합니다.mid = low + (high - low + 1) // 2n[mid] == target이면low = mid, 아니면high = mid - 1
n[low] == target이면low를 반환하고, 아니면 -1을 반환합니다.
3. 메인 로직
u := upper(arr, target)— 마지막 등장 위치l := lower(arr, target)— 첫 번째 등장 위치u != -1이고(u - l + 1) > len(nums) / 2이면true를 반환하고, 그렇지 않으면false를 반환합니다.
두 위치의 차이에 1을 더하면 타깃의 총 등장 횟수가 되며, 이 값이 배열 길이의 절반보다 큰지 비교하면 됩니다.
파이썬 구현 예제
다음 코드를 통해 실제 구현 방법을 살펴보겠습니다.
class Solution(object):
def upper(self, n, target):
low = 0
high = len(n) - 1
while low < high:
mid = low + (high - low + 1) // 2
if n[mid] == target:
low = mid
else:
high = mid - 1
return low if n[low] == target else -1
def lower(self, n, target):
low = 0
high = len(n) - 1
while low < high:
mid = low + (high - low) // 2
if n[mid] == target:
high = mid
else:
low = mid + 1
return high if n[high] == target else -1
def isMajorityElement(self, nums, target):
u = self.upper(nums, target)
l = self.lower(nums, target)
return u - l + 1 > len(nums) / 2 if u != -1 else False
ob1 = Solution()
print(ob1.isMajorityElement([2, 4, 5, 5, 5, 5, 5, 6, 6], 5))입력
[2, 4, 5, 5, 5, 5, 5, 6, 6] 5
출력
true
시간 복잡도 분석
이 알고리즘은 이진 탐색을 두 번 수행하므로 시간 복잡도는 O(log N)입니다. 배열을 한 번씩 순회하는 O(N) 방식보다 훨씬 효율적이며, 특히 배열이 이미 정렬되어 있다는 조건이 주어진 경우 최적의 선택입니다. 공간 복잡도 역시 추가 메모리를 사용하지 않으므로 O(1)입니다.