来源:Microsoft面试问题
给定一个排序数组,其中每个元素出现两次,除了一次出现的单元,我们需要找到该元素。
现在标准的O(n)解决方案是执行列表的异或,它将返回未重复的元素(因为所有重复的元素都会被取消。)
如果我们知道数组已经排序,是否有可能更快地解决这个问题?
答案 0 :(得分:14)
是的,你可以使用排序来通过二进制搜索将复杂性降低到O(log n)
。
由于数组已经排序,在缺失元素之前,每个值占据数组中的点2*k
和2*k+1
(假设基于0的索引)。
所以你转到数组的中间,比如索引h
,如果h+1
是偶数,则检查索引h
,如果h-1
,则检查h
是奇怪的。如果缺少的元素稍后出现,则这些位置的值相等,如果之前的值,则值不同。重复,直到找到缺失的元素。
答案 1 :(得分:6)
对数组执行二进制“搜索”(而不是遍历),检查两个邻居,如果两者都不同于中间的值,则可以使用解决方案。这是O(log n)
。
答案 2 :(得分:1)
是的,数组已排序,因此我们可以应用二进制搜索来查找单个元素。让我们看看单个元素的发生模式。元素总数始终为奇数,单个元素仅在偶数索引处出现
元素总数9,单个元素始终以偶数索引出现。
当(end_index - start_index) % 4 == 0
时,单个元素出现在中间。
if A[mid-1] == A[mid] --> single element left side
if A[mid] == A[mid+1] --> single element right side
元素总数11,单个元素始终以偶数索引出现。当(end_index - start_index) % 4 != 0
时,单个元素不在中间。
if A[mid] == A[mid+1] --> single element left
if A[mid-1] == A[mid] --> single element right
元素总数13,单个元素始终以偶数索引出现。当(end_index - start_index) % 4 == 0
时,单个元素也在中间出现。
if A[mid-1] == A[mid] --> single element left side
if A[mid] == A[mid+1] --> single element right side
下面是Python代码:
class Solution:
def singleNonDuplicate(self, A):
"""
:type nums: List[int]
:rtype: int
"""
L = len(A)
def binarySearch(A, start, end):
if start == end:
return A[start]
if start < end:
mid = int(start + (end - start)/2)
if A[mid-1] < A[mid] < A[mid+1]:
return A[mid]
if end - start == 2:
if A[end] != A[end-1]:
return A[end]
if end - start == 2:
if A[start] != A[start+1]:
return A[start]
if A[mid] == A[mid+1]:
if int(end-start)%4 == 0:
return binarySearch(A, mid+2, end)
else:
return binarySearch(A, start, mid-1)
elif A[mid-1] == A[mid]:
if int(end - start)%4 == 0:
return binarySearch(A, start, mid-2)
else:
return binarySearch(A, mid+1, end)
return binarySearch(A, 0, L-1)
if __name__ == "__main__":
s = Solution()
A = [1,1,2,3,3,4,4,5,5,6,6]
r = s.singleNonDuplicate(A)
print(r)