【集合】按照首字母来统计后半部分字符串的集合,如果两个集合之间的元素可以互换首字母,那么需要满足A集合中的没有在B中出现过,那么A集合中的元素才能换成B集合开头的字母,所以两个集合分别求补集,然后个数相乘即可,举个🌰:
假设统计完之后:
a: bb cc dd
b: cc ee ff
显然我们发现cc在B集合中出现过了,也就是说原本以a开头的cc不能换成以b开头的cc了,所以a中可以替换成b开头的元素只有bb、dd,同理,B集合中可以替换成a开头的字符只有cc和ff,这样形成的组合共计2*2个
class Solution {
// set 2:32 30
public long distinctNames(String[] ideas) {
long ans = 0;
Map<Integer, Set<String>> map = new HashMap();
for(var str: ideas){
var st = str.substring(1, str.length());
int c = str.charAt(0) - 'a';
if(map.containsKey(c)) map.get(c).add(st);
else {
Set<String> set = new HashSet();
set.add(st);
map.put(c, set);
}
}
for(var i = 0; i < 26; i++){
if(map.containsKey(i)){
Set<String> a = new HashSet(map.get(i));
for(var j = i + 1; j < 26; j++){
if(map.containsKey(j)){
Set<String> b = new HashSet(map.get(j));
Set<String> d = new HashSet(a);
d.removeAll(b);
b.removeAll(a);
ans += (long)d.size() * b.size() * 2;
}
}
}
}
return ans;
}
}
【预处理】直接通过哈希表来计算a开头的字符串替换成另外a-z开头的字符串共有多少个不在原来的字符串集合中。即建立一个26*26的二维数组记录以i开头的所有字符串替换成以j开头后不重复的有多少个。
class Solution {
// 3:35 15
public long distinctNames(String[] ideas) {
Set<String> set = new HashSet(){{
for(var x: ideas) add(x);
}};
int[][] arr = new int[26][26];
for(var x: ideas){
int i = x.charAt(0) - 'a';
var str = x.substring(1, x.length());
for(var j = 0; j < 26; j++){
var c = (char)(j + 'a');
if(!set.contains(c + str)){
arr[i][j]++;
}
}
}
long ans = 0;
for(var i = 0; i < 26; i++){
for(var j = 0; j < 26; j++){
ans += arr[i][j] * arr[j][i];
}
}
return ans;
}
}