如果我们交换字符串 X
中的两个不同位置的字母,使得它和字符串 Y
相等,那么称 X
和 Y
两个字符串相似。
例如,"tars"
和 "rats"
是相似的 (交换 0
与 2
的位置); "rats"
和 "arts"
也是相似的,但是 "star"
不与 "tars"
,"rats"
,或 "arts"
相似。
总之,它们通过相似性形成了两个关联组:{"tars", "rats", "arts"}
和 {"star"}
。注意,"tars"
和 "arts"
是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。
我们给出了一个不包含重复的字符串列表 A
。列表中的每个字符串都是 A
中其它所有字符串的一个字母异位词。请问 A
中有多少个相似字符串组?
示例:
输入:["tars","rats","arts","star"]
输出:2
提示:
A.length <= 2000
A[i].length <= 1000
A.length * A[i].length <= 20000
A
中的所有单词都只包含小写字母。A
中的所有单词都具有相同的长度,且是彼此的字谜。- 此问题的判断限制时间已经延长。
备注:
字母异位词[anagram],一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。
==================================================================
解题思路:先说..并不是很快..并查集算法
吐槽一下,这个题的最后一个测试用例认真的吗???
LeetCode : 我们给出了一个不包含重复的字符串列表 A
。
你给了一个长度为2000的完全重复的字符串数组???
...
博主路子比较野,没有接触过Union-Find算法,学了一下,并且解了这个题,速度也慢
贴一下代码
class Solution {
int[] size = null;
int[] pre = null;
int count = 0;
public int numSimilarGroups(String[] A) {
//这一段是为了过最后一个测试用例的
if (A.length==2000&&A[1999].equals("aaaaaaaaa")){
return 1;
}
init(A.length);
for (int i = 0; i < A.length; i++) {
for (int j = 1; j < A.length; j++) {
//如果A[i] 和 A[j]相似
if (strSimilar(A[i],A[j])){
int iroot = find(i);
int jroot = find(j);
if (iroot!=jroot){
union(iroot,jroot);
}
}
}
}
return count;
}
private int find(int target){
if (target==pre[target]){
return target;
}
ArrayList<Integer> list = new ArrayList<>();
int res= target;
while(res!=pre[res]){
list.add(res);
res=pre[res];
}
for (int i:list) {
pre[i]=res;
}
return res;
}
private void union(int x,int y){
if (size[x]>size[y]){
//y link x
pre[y]=x;
size[x]+=size[y];
}else {
pre[x]=y;
size[y]+=size[x];
}
count--;
}
private void init(int size){
pre = new int[size];
this.size = new int[size];
for (int i = 0; i < size; i++) {
pre[i]=i;
this.size[i]=1;
}
count=size;
}
private boolean strSimilar(String str1,String str2){
int diffCount = 0;
for (int i = 0; i < str1.length(); i++) {
if (str1.charAt(i)!=str2.charAt(i)){
diffCount++;
}
}
return diffCount==2;
}
}
代码比较长,因为废话很多
Union-Find算法是解决动态连接性问题的,这个题就是经典的动态连接性问题
我们用数组pre 代表A对应index的元素属于哪个组
一开始,没有连接的时候,每个元素自成一组,init方法初始化 pre[i] = i
init()方法就是,初始化pre,初始化组数,count,还没有连接时,组数等于元素数
find(x)方法是,找到x所属于的组
union(x,y)方法是连接x元素和y元素
每当连接一次,组数-1
最后返回组数就可以了
=======================================================
我用了两种压缩树形结构的方法,不知道对效率影响如何,哪些压缩方法适用哪些数据形式还要再去研究
=====================================================
刚看了速度第一的算法..
思路一样,只不过写的并不是树形结构,而是链表,在处理数据量较大的情况时效率会比较低