540. Single Element in a Sorted Array
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
answer = 0
for num in nums:
answer = xor(answer, num)
return answer
친절하게도 하나의 정수를 제외한 모든 정수는 두 개씩 나온다. 나와 나 자신을 xor
한 연산은 0이 나오며, 따라서, 주어진 배열 nums
를 모두 xor
연산하게 되면 하나만 존재하는 숫자를 찾을 수 있게 된다.
reduce
함수를 이용하면 다음과 같이 한 줄로 작성도 가능하다.
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
return reduce(xor, nums)
O(N)
O(1)
해당 문제는 시간 복잡도 O(N)
으로도 충분히 풀 수 있는 문제다.
하지만, 문제에서 제시하는 시간 복잡도는 O(logn)
이다. 따라서, O(logn)
을 만족하는 접근법을 찾아야 한다.
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 2
while left <= right:
mid = (left + right) // 2
if mid % 2: # odd
if nums[mid] == nums[mid-1]:
left = mid + 1
else:
right = mid - 1
else: # even
if nums[mid] == nums[mid+1]:
left = mid + 1
else:
right = mid - 1
return nums[left]
시간 복잡도 log(n)
을 만족하기 위해 이분탐색
을 이용한다.
주어지는 nums
는 오름차순으로 정렬이 되어 있으며, 어느 정도 규칙성이 보이는 배열이다.
어떠한 조건에 따라 left
, right
값을 이동시킬지가 관건이다. 두 번째 예제를 잘 살펴본다면 규칙이 보인다.
nums = [3,3,7,7,10,11,11]
배열에서, single element
인 10
이 나타나기 전인 [3,3,7,7]
을 봐보자.
mid
값이 짝수
일 경우,
- mid
값이 0 혹은 2일 경우, nums[0] = nums[1]
, nums[2] = nums[3]
인 규칙을 보인다.
mid
값이 홀수
일 경우,
- mid
값이 1 혹은 3일 경우, nums[1] = nums[0]
, nums[3] = nums[2]
인 규칙을 보인다.
즉, mid 값이 짝수라면 nums[mid] = nums[mid+1]
, mid 값이 홀수라면 nums[mid] = nums[mid-1]
인 패턴을 찾을 수 있다.
단일 숫자가 나온다면 이 패턴은 깨지게 되며, 이에 따라 left
, right
값을 조절하며 O(logN)
안에 단일 숫자를 찾을 수 있게 된다.
O(logN)
O(1)