每日一题|2306. 公司命名|哈希映射、集合运算
本题可以预想暴力解法是遍历整个数组,分别进行匹配,这样的复杂度是O(n^2),必然超时。
所以想到如何进行时间上的简化。
对于遍历进行求解,时间主要消耗在“模拟这个过程上”,也就是真的去匹配,而没有关注到题目让求解到仅仅是“数量”。也就是说,如果能够直接从数量上进行运算,将会很方便,也很高效。
对于一个数组内的两个元素,strA和strB,交换它们的首字母后,对应的分别是pre_A + suf_B 和 pre_B + suf_A。那么我们扩展数量,preA在数组中有a个后缀,preB在数组中有b个后缀(pre_A不等于pre_B)。也就是说pre_A可以引导一个集合A,数量是a;pre_B可以引导一个集合,B数量是b。
此时,问题已经转化为数量上的计算。
那么对于A而言,如果交换到pre_B引导,则能够有效的后缀数量是B的数量减去A和B交集的数量。或者说交换后有效的集合是B - (A&B)。同理,B交换到A仍然有效的数量是A - (A&B)。
那么此时,两个集合是等价的,其中每一个配对,都构成一个有效的题目所求的名字组合。
注意,我们要求的仍然是数量,所以ans_(A,B) = |B - (A&B)| * |A - (A&B)|。遍历全部的A和B组合即可。
1.构建哈希映射关系
构建由前缀作为key,后缀作为value的哈希。这里采用字典的方式,默认值位空集合set。
names = defaultdict(set)
for idea in ideas:
names[idea[0]].add(idea[1:])
2.遍历所有可能的前缀组合
for pre_a, set_a in names.items():
for pre_b, set_b in names.items():
if pre_a == pre_b:
continue
else:
intersect = set_a & set_b # 交集运算
ans += (len(set_a) - len(intersect)) * (len(set_b) - len(intersect))
这里注意集合运算&表示交集的写法。
完整代码如下:
class Solution(object):
def distinctNames(self, ideas):
"""
:type ideas: List[str]
:rtype: int
"""
names = defaultdict(set)
for idea in ideas:
names[idea[0]].add(idea[1:])
ans = 0
for pre_a, set_a in names.items():
for pre_b, set_b in names.items():
if pre_a == pre_b:
continue
else:
intersect = set_a & set_b # 交集运算
ans += (len(set_a) - len(intersect)) * (len(set_b) - len(intersect))
return ans