2306. 公司命名(leetCode_每日一题)

2306. 公司命名

给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下:

  1. 从 ideas 中选择 2 个 不同 名字,称为 ideaA 和 ideaB 。
  2. 交换 ideaA 和 ideaB 的首字母。
  3. 如果得到的两个新名字  不在 ideas 中,那么 ideaA ideaB串联 ideaA 和 ideaB ,中间用一个空格分隔)是一个有效的公司名字。
  4. 否则,不是一个有效的名字。

返回 不同 且有效的公司名字的数目。

示例 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


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值