2306. 公司命名

给你一个字符串数组 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 。

解题思路:
1.常规思路,双重遍历,拼接首字母组成,判断是否符合题目条件,符合则增加

代码:
    class Solution {
        public long distinctNames(String[] ideas) {
            long ans = 0;
            List<String> list = new ArrayList<>();
            Collections.addAll(list, ideas);
            int length = ideas.length;
            for (int i = 0; i < length; i++) {
                String s = ideas[i];
                for (int j = 0; j < length; j++) {
                    String s1 = ideas[j];
                    if (s.charAt(0) != s1.charAt(0)) {
                        StringBuilder sb = new StringBuilder(s);
                        sb.setCharAt(0, s1.charAt(0));

                        StringBuilder sb1 = new StringBuilder(s1);
                        sb1.setCharAt(0, s.charAt(0));
                        if (!list.contains(sb.toString()) && !list.contains(sb1.toString())) {
                            ans++;
                        }
                    }
                }
            }
            return ans;
        }
    }

  这种结果正确但是运行必然是超时
  优化思路:
      1.使用Map存储不同首字符及其对应的字符串后缀集合
      2.遍历每个首字符及其对应后缀集合,计算与其他首字符后缀集合无交集的元素数量
      3.根据无交集元素数量计算不相似名字对数,并返回最终结果。

  完整代码:
      class Solution {
        public long distinctNames(String[] ideas) {
            // 使用Map存储以不同字符开头的字符串集合
            Map<Character, Set<String>> map = new HashMap<>();
            // 遍历所有字符串,根据首字符进行分类存储
            for (String idea : ideas) {
                // 获取当前字符串的首字符
                char firstChar = idea.charAt(0);
                // 获取除首字符外的剩余字符串
                String suffix = idea.substring(1);
                // 如果Map中尚未存在该首字符的键,則创建一个新的HashSet,并添加剩余字符串
                map.computeIfAbsent(firstChar, k -> new HashSet<>()).add(suffix);
            }


            // 计算不相似的名字对数
            long ans = 0;
            // 遍历Map中的每个首字符
            for (Character c1 : map.keySet()) {
                // 获取以当前首字符开头的字符串集合
                Set<String> set1 = map.get(c1);
                // 遍历其他首字符
                for (Character c2 : map.keySet()) {
                    // 跳过相同的首字母,因为我们需要比较不同的组
                    if (c1.equals(c2)) continue;
                    // 获取以另一个首字符开头的字符串集合
                    Set<String> set2 = map.get(c2);

                    // 计算两个集合中没有交集的元素数量
                    long count1 = 0;
                    // 统计set1中不在set2中的元素数量
                    for (String s : set1) {
                        if (!set2.contains(s)) {
                            count1++;
                        }
                    }

                    long count2 = 0;
                    // 统计set2中不在set1中的元素数量
                    for (String s : set2) {
                        if (!set1.contains(s)) {
                            count2++;
                        }
                    }

                    // 计算不相似的名字对数,避免重复计算
                    ans += count1 * count2;
                }
            }
            // 返回不相似的名字对数
            return ans;
        }
    }
posted @ 2024-09-25 11:00  JAVA-CHENG  阅读(19)  评论(0编辑  收藏  举报