面试常考题,最近几天滴滴和百度都被问过.
机智如我第一时间想到的最蠢的方法就是,遍历字符串,判断当前字符是否在后面的字符串中出现。
def first_uniq(s):
for i in range(len(s)):
if s[i] not in s[i+1:]:
return(s[i])
这样写,时间复杂度O( n2),而且‘aaaaaaaaaaaaabc’这种字符串会返回‘a'。真是蠢啊,排个序再遍历判断s[i] !=s[i+1]都比这个强。
然后自然想到用字典统计一下每个字符出现的次数,节省点儿行数用了collections 中的defaultdict。
def first_uniq(s):
cnter = defaultdict(lambda:0)
for i in s:
cnter[i] += 1
for i in s:
if cnter[i] == 1:
return i
但是还是需要loop 2次。
*************** 后面这俩不大好 想到好的方法再改 “如果别的语言没有OrderedDict数据类型怎么办,自己复写一个?”****************
限制只执行一次loop怎么办,因为字典是无序,其实只需要在我们的字典里维护一个‘字符’出现顺序就可以了,自然想到了OrderedDict.
def first_uniq(s):
cnter = OrderedDict()
for i in s:
if i in cnter:
cnter.move_to_end(i)
cnter[i] += 1
else:
cnter[i] = 1
return list(cnter)[0]
那么问题又出现了,只有最后一个数只出现一次,如‘abcabcabch’这种输入的时候还是会有问题。return的时候做一下判断, 或者再维护一个字典。
cnt_list = list(cnter)
if cnt_list[0] == 1:
return cnt_list[0]
elif cnt_list[-1] == 1:
return cnt_list[-1]
else:
return None
def first_uniq(s):
cnter_1 = OrderedDict()
cnter_other = OrderedDict()
for i in s:
if i in cnter_other:
cnter_other[i] += 1
elif i in cnter_1:
cnter_1.pop(i)
cnter_other[i] = 2
else:
cnter_1[i] = 1
if cnter_1:
return list(cnter_1)[0]
else:
return None