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;
}
}