给定一个字符串,里面的字符都是成对出现,除了一个,要求找到这个单独出现的字符。
比如“AABBCCDDE”,返回“E”。
当然可以遍历,看当前元素是否和后面的字符一样,不一样就返回,这样的时间复杂度是 O ( n ) O(n) O(n)。还有时间效率更高的方法,可以用二分查找。
可以观察到,整个字符串长度n一定是奇数,且如果是成对的,每个偶数下标处的字符和紧挨着它后面的奇数字符应该是一样的。当我们用二分查找,mid=n/2(向下取整),比较mid,和mid-1处的字符是否一样。
为什么是比较mid和mid-1处的字符,因为mid处是整个串的中间位置,如果和mid-1处的字符一样,意味着mid和mid-1处的字符是一对,mid-1前面有奇数个字符,则单独的字符就在前半段,则将查询范围转移到前半段。
同理,若mid和mid-1处的字符不同,且mid和mid+1处的不同,则单独的字符就在后半段,将查询范围转移到后半段。
当然还要注意一些特殊情况,比如,可以先查询单个字符是不是在首位处、正中间处。
所以我不是很明白下面这个博客里的代码,他的逻辑和我的正好是反着的。
https://blog.csdn.net/hxqneuq2012/article/details/52699913
下面我写了一个粗糙的代码(需要特别注意的地方就是每次更新的start,end与mid的关系):
def findsingel(a,n):
start=0
end=n//n是字符串长度
if(a[0]!=a[1]):
return a[0]
if(a[n-2]!=a[n-1]):
return a[n-1]
while(start<end-1):
mid=int((start+end-1)/2)
if(a[mid]==a[mid-1]):
end=mid-1
else :
if(a[mid]!=a[mid-1] and a[mid]!=a[mid+1]):
return a[mid]
else:
start=mid+2
return a[start]
//测试用例
e="AABBCCDEEFFGG"//单独字符在正中间
f="AABCCDDEEFFGG"/单独字符在左半段
g="AABBCCDDEEFGG"/单独字符在右半段
print(findsingel(e,len(e)),'---D')
print(findsingel(f,len(f)),'---B')
print(findsingel(g,len(g)),'---F')
输出如下图: