leetcode 1061. 按字典序排列最小的等效字符串 中等
给出长度相同的两个字符串s1
和 s2
,还有一个字符串 baseStr
。
其中 s1[i]
和 s2[i]
是一组等价字符。
- 举个例子,如果
s1 = "abc"
且s2 = "cde"
,那么就有'a' == 'c', 'b' == 'd', 'c' == 'e'
。
等价字符遵循任何等价关系的一般规则:
- 自反性 :
'a' == 'a'
- 对称性 :
'a' == 'b'
则必定有'b' == 'a'
- 传递性 :
'a' == 'b'
且'b' == 'c'
就表明'a' == 'c'
例如, s1 = "abc"
和 s2 = "cde"
的等价信息和之前的例子一样,那么 baseStr = "eed"
, "acd"
或 "aab"
,这三个字符串都是等价的,而 "aab"
是 baseStr
的按字典序最小的等价字符串
利用 s1
和 s2
的等价信息,找出并返回 baseStr
的按字典序排列最小的等价字符串。
示例 1:
输入:s1 = "parker", s2 = "morris", baseStr = "parser" 输出:"makkek"
示例 2:
输入:s1 = "hello", s2 = "world", baseStr = "hold" 输出:"hdld"
示例 3:
输入:s1 = "leetcode", s2 = "programs", baseStr = "sourcecode" 输出:"aauaaaaada"
提示:
1 <= s1.length, s2.length, baseStr <= 1000
s1.length == s2.length
- 字符串
s1
,s2
, andbaseStr
仅由从'a'
到'z'
的小写英文字母组成。
分析:并查集的应用。将 26 个字符映射到 0~25 上,初始时,每个字符都指向自己。接着遍历 s1 字符串,将 s1 和 s2 对应位置的字符合并,每次合并,根节点都取字典序较小的值。遍历完后,再进行一次路径压缩。最后遍历 baseStr,输出对应字符的集合中的最小字符。
int findf(int x,int flag[])
{int a=x;while(x!=flag[x])x=flag[x];while(a!=flag[a]){int z=a;a=flag[a],flag[z]=x;}return x;
}void merge(int a,int b,int flag[])
{int fa=findf(a,flag);int fb=findf(b,flag);if(fa!=fb){if(fa<fb)flag[fb]=fa;else flag[fa]=fb;}
}char* smallestEquivalentString(char* s1, char* s2, char* baseStr) {int flag[30];for(int i=0;i<26;++i)flag[i]=i;for(int i=0;s1[i];++i)if(flag[s1[i]-'a']!=flag[s2[i]-'a'])merge(s2[i]-'a',s1[i]-'a',flag);for(int i=0;i<26;++i)flag[i]=findf(i,flag);for(int i=0;baseStr[i];++i)baseStr[i]=flag[baseStr[i]-'a']+'a';return baseStr;
}