变位词的判断问题
字母相同,但是顺序不同的词就是变位词,如
earth和heart
abcde和badec
地球 和 球地
解法1 逐位比较
有两个串s1和s2,看s1中的元素在s2中有没有出现,如果没有出现不是变位词,出现了的话在s2中做个标记,说明这个元素已经有主了 ,避免后面的s1中的元素误判(如s1 = “aa” s2 = “ab” 的话 不在s2中的第一个a判断之后打上标记的话,后面s1中的第二个a又会认为在s2中找到了它的Mr.Right,最后判断出两个串是变位词, which is actually wrong! )
除此之外,也可以一开始就检查两个串的字符个数相不相等一类的前提
算法用双层循环实现,时间复杂度是O(n^2)
def anagramSolution(s1, s2):
if len(s1) != len(s2):
return False
else:
# 将s2字符串转为list 这个可以改变其中的每一个元素
s2_list = list(s2)
# 每个s1中的元素都要逐个与s2中的元素做对比
for item in s1:
i = 0
while i < len(s2_list):
# 在s2中找到了 把s2中的这个元素设为None 防止下次重复和这个元素对比
if item == s2_list[i]:
s2_list[i] = None
break
i += 1
# 要是下标i达到了s2的元素个数的话 说明遍历完了 也没有找到
if i == len(s2_list):
# print(item,s2_list[i])
return False
return True
做这个印象比较深的就是,python的for循环和c++的for循环不一样,如果在c++中检查数组的最后一个元素是否遍历到,我可以在循环体之外检查一个循环变量是否等于数组的长度了,等于数组的长度的话,说明循环变量到超过数组的下标了结束循环的,数组的最后一个元素遍历到了,不然就是没有, 但是python的for循环直接给的for i in range(len(array)),循环变量不会出现等于数组长度的情况,所以可以修改一下判断条件或者改成while循环,适配我的程序的话改成while循环更好,不然的话后面的判断条件要写的很麻烦(我的风格是在循环体里面给判断条件,满足条件的话就跳出去,然后循环体结束之后,就可以通过遍历变量的大小来确定这个是满足条件跳出来的,还是不满足循环条件了跳出来的
解法2 排序比较
先排序再比较 利用列表的sort()方法的话,时间复杂度是O(nlogn)
def anagramSolution2(s1, s2):
if len(s1) != len(s2):
return False
# 将s1和s2都转成列表 然后排序 排序后的结果相同的就是变位词 不相同的就不是变位词
s1_list = list(s1)
s2_list = list(s2)
s1_list.sort()
s2_list.sort()
return s2_list == s1_list
解法3 暴力枚举法
列举出串s1所有的变位词,然后看s2是否在其中,首先就是要做出s1的所有组合串,共有n!个,算法的时间复杂度是O(n!)
解法4 计数器法
给每一个英文字母都给一个计数器,最后比较这些个计数器是否是相等的,算法的时间复杂度是O(n)
# param 字符串
# return 大小为26的列表 表示从a到Z每一个字母在串中出现的个数
def characterList(s):
# 快速赋值列表的方法
result = [0]*26
for i in s:
result[ord(i)-97] += 1
return result
def anagramSolution3(s1, s2):
return characterList(s1) == characterList(s2)
python数据类型的性能
列表list的底层是数组,因此适合于直接根据索引取值O(1),不适合在非末端插入和删除O(n)
字典dict的底层是hash实现的,所以只要是涉及到算hash的时间复杂度都是O(1)