给你一个字符串数组 ideas
表示在公司命名过程中使用的名字列表。公司命名流程如下:
- 从
ideas
中选择 2 个 不同 名字,称为ideaA
和ideaB
。 - 交换
ideaA
和ideaB
的首字母。 - 如果得到的两个新名字 都 不在
ideas
中,那么ideaA ideaB
(串联ideaA
和ideaB
,中间用一个空格分隔)是一个有效的公司名字。 - 否则,不是一个有效的名字。
返回 不同 且有效的公司名字的数目。
示例 1:
输入:ideas = ["coffee","donuts","time","toffee"] 输出:6 解释:下面列出一些有效的选择方案: - ("coffee", "donuts"):对应的公司名字是 "doffee conuts" 。 - ("donuts", "coffee"):对应的公司名字是 "conuts doffee" 。 - ("donuts", "time"):对应的公司名字是 "tonuts dime" 。 - ("donuts", "toffee"):对应的公司名字是 "tonuts doffee" 。 - ("time", "donuts"):对应的公司名字是 "dime tonuts" 。 - ("toffee", "donuts"):对应的公司名字是 "doffee tonuts" 。 因此,总共有 6 个不同的公司名字。 下面列出一些无效的选择方案: - ("coffee", "time"):在原数组中存在交换后形成的名字 "toffee" 。 - ("time", "toffee"):在原数组中存在交换后形成的两个名字。 - ("coffee", "toffee"):在原数组中存在交换后形成的两个名字。
示例 2:
输入:ideas = ["lack","back"] 输出:0 解释:不存在有效的选择方案。因此,返回 0 。
提示:
2 <= ideas.length <= 5 * 104
1 <= ideas[i].length <= 10
ideas[i]
由小写英文字母组成ideas
中的所有字符串 互不相同
解:
读题:
ideas截取两个idea_a和idea_b,如果交换首字母, 得到的字符不在ideas集合中出现,视为有效.
求有效公司名数目.
既然要进行首字母交换了,肯定需要把首字母对应的集合罗列出来,
c对应(offee),d对应(onuts),t对应(ime,offee)
同时我们也把结尾字符对应的首字母罗列出来.
offee对应(c,t),onuts对应(d),ime对用(t)
错误❎尝试仅供参考:
我们可以从结尾字符去考虑,比如offee.
我们拿到offee, 对应字符为(c,t).个数为2个.
那么c/t开头的字符都不计算个数. 出去c/t之外只有d,有一个字符. 可以组合两种组合.coffee/donuts和toffee/donuts
ime对应的字符为(t).
那么t开头的字符都不计算个数.time能和coffee交换吗? 不能交换,为啥?
因为offee对应的为(c/t)包含了t.所以time也不能和coffee
第一层遍历ime,第二层遍历所有首字母的集合(c/d/t),第三层遍历首字符集合对应的结尾值(c对应的offee; d对应的onuts).第四层遍历结尾值里面是否包含当前的首字符(offee对应的c/t;onuts对应的d).
四层循环遍历,还是预期之中的"超出时间限制"
从结尾字符考虑算法失败,能否从开始字符去考虑呢?
将c开头的集合视为一个整体. 统一的去和t开头的集合进行替换.
如果能全部替换完毕,最大组合=len(c)*len(t)但是其中可能存在重复的数据啊!
比如c中包含offee,t中也包含offee,那么两遍的offee替换之后肯定还是在ideas中的,所以需要先剔除重复的数据.有效组合个数=(len(c)-重复个数)*(len(t)-重复个数)
c/d = (1-0)*(1-0)=1条.(coffee/donuts)
c/t = (1-1)*(2-1)=0条.()
d/c = (1-0)*(1-0)=1条.(donuts/coffee)
d/t = (1-0)*(2-0)=2条.(donuts/time;donuts/toffee)
t/c = (2-1)*(1-1)=0条.()
t/d = (2-0)*(1-0)=2条.(time/donuts;toffee/donuts)
合计条数=6条.最大的遍历次数=26*26=676次.效果杠杠的.
python代码
def distinctNames(self, ideas: List[str]) -> int:
# 制作前缀对应的集合。
_first_map = {}
for idea in ideas:
first = idea[0:1]
end = idea[1:]
if not _first_map.__contains__(first):
_first_map.setdefault(first, set())
_first_map.get(first).add(end)
result = 0
# 双层嵌套遍历,进行first1和first2相互替换的尝试。
for first1, end_list1 in _first_map.items():
for first2, end_list2 in _first_map.items():
# 去除相同元素。
if first1 == first2:
continue
# 两边的集合公共元素有多少
public = len(end_list1 & end_list2)
# 累加去除公共元素之后的乘积。
result += (len(end_list1) - public) * (len(end_list2) - public)
return result