给定一个英语词典,找出其中所有变位词集合。例如,“pots”、“stops”、和“tops”互为变位词,因为每一个单词都可以通过改变其他单词中字母的顺序得到
。
为了将问题简化,我们不需要对比英文词典,判断"otsp"是不是一个合法的单词(这个显然不是),因为这没有太大的意义。因此我们将问题简化为,给定任意两个英文单词word1和word2,判断是否互为变位词。
这是一个很简单,但是很具有代表性的问题,因为这个问题的解决办法很多,优化空间很大。
暴力破解
- 首先,我们面对这种题目,如果没有思路,第一个解法就是暴力破解,这也是第一种方法,那么怎么暴力破解呢?答案就是全排列,找出word1组成字母的全排列,判断word2在不在该全排列里面。
# 全排列
#空间复杂度:O(n!),时间复杂度:O(n!)
word1 = 'deposit'
word2 = 'topside'
word3 = 'visited'
res = []
def full_array(word, temp=''):
if len(word)==0:
if word not in res:
res.append(temp)
return
for i in range(len(word)):
temp += word[i]
full_array(word[:i]+word[i+1:], temp)
temp = temp[:-1]
def heterotopic_words_full_array(word1, word2):
if len(word1) != len(word2):
return 'no'
full_array(word1)
return 'yes' if word2 in res else 'no'
遍历
- 我们接着思考,能不能优化一下?答案也是可以的。我们可以对两个word进行遍历,只要word1的字母出现在word2中,就在word2该字母所在位置进行一次标识,比如置为0,当遍历完成,我们只需要判断word2的所有位置是不是全为0即可。
# 遍历
#空间复杂度:O(n),时间复杂度:O(n^2)
def heterotopic_words_ergodic(word1, word2):
if len(word1) != len(word2):
return 'no'
word2 = list(word2)
for c in word1:
for i in range(len(word2)):
if c == word2[i]:
word2[i] = 0
for c in word2:
if c != 0:
return 'no'
return 'yes'
heterotopic_words_ergodic(word1, word2)
排序
- O(n2)的时间复杂度还是太高了,能不能再优化一下?答案也是可以的。考虑到所有的字母都是按照 ASCII 或者 Unicode 进行编码,所以在内存中,字母对应的其实是一个int型数字(可以用ord(“a”)查看对应数字编码)。也就是说我们可以对两个word进行排序,然后比较两个word是不是相等即可。
# 排序
#空间复杂度:O(n),时间复杂度:O(nlog n)
def heterotopic_words_sort(word1, word2):
if len(word1) != len(word2):
return 'no'
word1 = ''.join(sorted(word1))
word2 = ''.join(sorted(word2))
return "yes" if word1==word2 else "no"
heterotopic_words_sort(word1, word3)
排序
- O(nlogn)的时间复杂度还是有点高了,能不能再优化一下?答案也是可以。考虑到互为变位词的两个单词必然有同样的字母构成,并且相同字母的数量相等,所以我们考虑给每一个字母加上一个标识,每当在word1中遇到,就+1,在word2中遇到,就-1,如果最后遍历一遍之后,该标识对应的value为0,表示该字母在两个单词中的数量是一致的。也就是说,我们需要确定所有字母的value是不是都为0,就能判断两个单词是不是互为变位词。
# 哈希
#空间复杂度:O(n),时间复杂度:O(n)
from collections import defaultdict
def heterotopic_words_hash(word1, word2):
if len(word1) != len(word2):
return 'no'
hash_dict = defaultdict(int)
for i in range(len(word1)):
hash_dict[word1[i]] += 1
hash_dict[word2[i]] -= 1
for key in hash_dict.keys():
if hash_dict[key] != 0:
return 'no'
return 'yes'
heterotopic_words_hash(word1, word3)
那么时间复杂度到O(n)是不是就到头了呢?我觉得应该不是的,限制程序员的永远是思维,可能过段时间就能提出一种O(log n)的优化方法了。