惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
D
Docker
月光博客
月光博客
MongoDB | Blog
MongoDB | Blog
Vercel News
Vercel News
美团技术团队
博客园 - 叶小钗
I
InfoQ
Jina AI
Jina AI
博客园 - 司徒正美
雷峰网
雷峰网
B
Blog
Y
Y Combinator Blog
A
About on SuperTechFans
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
Microsoft Security Blog
Microsoft Security Blog
Stack Overflow Blog
Stack Overflow Blog
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Recent Announcements
Recent Announcements
V
V2EX
N
Netflix TechBlog - Medium

Moon's Blog

Java内存 | Moon's Blog Spring Data JPA | Moon's Blog Spring Boot的Java Config | Moon's Blog Java知识点 | Moon's Blog Spring Boot知识点 | Moon's Blog Java异常机制 | Moon's Blog Java的类加载器 | Moon's Blog JVM类加载机制 | Moon's Blog 单体架构与微服务架构 | Moon's Blog 424.替换后的最长重复字符 | Moon's Blog 888.公平的糖果棒交换 | Moon's Blog 778.水位上升的泳池中游泳 | Moon's Blog 1631.最小体力消耗路径 | Moon's Blog 724.寻找数组的中心索引 | Moon's Blog 使用Jackson库实现日期序列化 | Moon's Blog 使用Jackson库实现Java多态解析 | Moon's Blog Spring Boot+InfluxDB实现日志管理 | Moon's Blog Java多态+工厂模式实现服务调用 | Moon's Blog 为Spring Boot项目生成OpenAPI3.0文档 | Moon's Blog
839.相似字符串组 | Moon's Blog
Moon Lou · 2021-02-01 · via Moon's Blog

839.相似字符串组

题目

如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。

例如,”tars” 和 “rats” 是相似的 (交换 0 与 2 的位置); “rats” 和 “arts” 也是相似的,但是 “star” 不与 “tars”,”rats”,或 “arts” 相似。

总之,它们通过相似性形成了两个关联组:{“tars”, “rats”, “arts”} 和 {“star”}。注意,”tars” 和 “arts” 是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。

给你一个字符串列表 strs。列表中的每个字符串都是 strs 中其它所有字符串的一个字母异位词。请问 strs 中有多少个相似字符串组?

示例 1:

输入:strs = [“tars”,”rats”,”arts”,”star”]
输出:2

示例 2:

输入:strs = [“omv”,”ovm”]
输出:1

提示:

  • 1 <= strs.length <= 100
  • 1 <= strs[i].length <= 1000
  • sum(strs[i].length) <= 2 * 104
  • strs[i] 只包含小写字母。
  • strs 中的所有单词都具有相同的长度,且是彼此的字母异位词。

备注:

​ 字母异位词(anagram),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。

思路

首先贴一下知乎大佬对并查集的详细解读。

只要A和B相似,B和C相似,即使A和C不相似,ABC也是一组。映射到图论中,就是妥妥的求联通集数目的问题,不多BB直接上并查集

  • 首先解决下如何判断两个字符串相似的问题。很简单,相似的两个字符串,只有两个位置上的字符不一样,其他位置都是一样的,问题解决。
  • 然后解决求联通集数目的问题。所有的字符串两两比较,如果同属于一个联通集(根节点相同),直接不用比了;如果两个字符串不属于同一个联通集且相似,那么合并这两个联通集(一个联通集的根节点认另一个联通集的根节点做爹)。最后统计联通集的总数(统计根节点的数目),问题解决。

解决第一个问题,为了比较两个字符串是否相似,需要O(m)的时间,m是每个字符串的长度;那么两两比较需要O(mn^2)的时间,n是字符串的总数;解决第二个问题,最坏情况下需要对并查集进行O(n)次合并,合并的均摊时间复杂度为O(logn),logn也就是节点数为n的树的高度(相当于找到根节点的时间)。总的时间复杂度是O(mn^2 + nlogn)

代码

class Solution {
private int[] f;

public int numSimilarGroups(String[] strs) {

f = new int[strs.length];
for (int i = 0; i < strs.length; ++i) {
f[i] = i;
}


for (int i = 0; i < strs.length; ++i) {
for (int j = i + 1; j < strs.length; ++j) {
if (find(i) == find(j)) {
continue;
} else if (check(strs[i], strs[j], strs[0].length())) {
f[find(i)] = find(j);
}
}
}


int num = 0;
for (int i = 0; i < strs.length; ++i) {
if (f[i] == i) {
++num;
}
}
return num;
}


private int find(int x) {
return x == f[x] ? x : (f[x] = find(f[x]));
}


private boolean check(String str1, String str2, int length) {
int count = 0;
for (int i = 0; i < length; ++i) {
if (str1.charAt(i) != str2.charAt(i)) {
++count;
}
if (count > 2) {
return false;
}
}
return true;
}
}

版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Moon's Blog