欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 锐评 > 【每日一题】LeetCode 2306.公司命名(位运算、数组、哈希表、字符串、枚举)

【每日一题】LeetCode 2306.公司命名(位运算、数组、哈希表、字符串、枚举)

2024/10/24 19:03:17 来源:https://blog.csdn.net/Hanbuhuic/article/details/142532539  浏览:    关键词:【每日一题】LeetCode 2306.公司命名(位运算、数组、哈希表、字符串、枚举)

【每日一题】LeetCode 2306.公司命名(位运算、数组、哈希表、字符串、枚举)

题目描述

给定一个字符串数组 ideas,表示在公司命名过程中使用的名字列表。我们需要从 ideas 中选择两个不同的名字,称为 ideaAideaB。然后交换 ideaAideaB 的首字母。如果交换后得到的两个新名字都不在 ideas 中,那么这两个名字串联起来(中间用一个空格分隔)就是一个有效的公司名字。我们需要返回不同且有效的公司名字的总数。

在这里插入图片描述

输入示例

示例 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 * 10^4
  • 1 <= ideas[i].length <= 10
  • ideas[i] 由小写英文字母组成
  • ideas 中的所有字符串互不相同

思路分析

  1. 遇到困难题,我们先可以尝试暴力枚举,然后再逐步优化!
  2. 首先,我们将 ideas 数组中的所有字符串添加到一个 HashSet 中,以便快速检查某个字符串是否在 ideas 中。
  3. 然后,我们使用两层循环遍历 ideas 数组,外层循环选择 ideaA,内层循环选择 ideaB
  4. 对于每一对 ideaAideaB,我们交换它们的首字母,得到两个新的名字 newIdea1newIdea2
  5. 我们检查这两个新名字是否都不在 ideas 中。如果不在,那么这是一个有效的公司名字,计数器 count 增加。
  6. 由于每一对 ideaAideaB 可以交换两次(ideaAideaBideaBideaA),所以我们需要将最终的计数器 count 乘以 2。

代码实现(暴力枚举)

class Solution {public long distinctNames(String[] ideas) {// 将所有名字存入HashSet中,方便快速查找HashSet<String> set = new HashSet<>();for (String idea : ideas) {set.add(idea);}// 初始化计数器long count = 0;int n = ideas.length;// 外层循环遍历选择ideaAfor (int i = 0; i < n; i++) {char firstChar1 = ideas[i].charAt(0); // 获取ideaA的首字母// 内层循环遍历选择ideaB,从i+1开始避免重复for (int j = i + 1; j < n; j++) {char firstChar2 = ideas[j].charAt(0); // 获取ideaB的首字母// 交换首字母后的新名字String newIdea1 = firstChar2 + ideas[i].substring(1);String newIdea2 = firstChar1 + ideas[j].substring(1);// 如果两个新名字都不在ideas中,那么这是一个有效的公司名字if (!set.contains(newIdea1) && !set.contains(newIdea2)) {count++;}}}// 由于每一对可以交换两次,所以最终结果需要乘以2return count * 2;}
}

思路优化

  1. 我们可以使用一个数组 groups 来存储按首字母分组的后缀。
  2. 遍历 ideas 数组,将每个字符串的后缀(去掉首字母的部分)添加到对应的 HashSet 中。
  3. 使用两层循环遍历 groups 数组,外层循环选择首字母 i,内层循环选择首字母 j(从 i+1 开始,避免重复计算)。
  4. 对于每一对首字母 ij,我们统计它们共有的后缀数量 m
  5. 计算可以形成的不同名称的数量,即 (groups[i].size() - m) * (groups[j].size() - m)
  6. 由于每一对 ideaAideaB 可以交换两次(ideaAideaBideaBideaA),所以我们需要将最终的计数器 count 乘以 2。

代码实现(思路优化)

class Solution {public long distinctNames(String[] ideas) {// 开一个set数组存储后缀HashSet<String>[] groups = new HashSet[26];for (int i = 0; i < 26; i++) {groups[i] = new HashSet<>(); }// 将每个字符串的后缀按照首字母分组for (String str : ideas) {groups[str.charAt(0) - 'a'].add(str.substring(1)); // 将后缀加入到对应的 HashSet 中}long count = 0;// 两层循环遍历所有可能的首字母组合for (int i = 0; i < 26; i++) {for (int j = i + 1; j < 26; j++) {int m = 0; // 计数相同后缀的数量// 统计 i 组和 j 组中相同的后缀数量for (String s : groups[i]) {if (groups[j].contains(s)) {m++;}}// 计算 i 组和 j 组可以形成的不同名称的数量count += (long)((groups[i].size() - m) * (groups[j].size() - m));}}return count * 2; // 每对组合可以有两种排列,因此乘以 2}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com