文章目录
- 1. 题目
- 2. 解题
1. 题目
给你一个下标从 0 开始的字符串数组 words 。
每个字符串都只包含 小写英文字母 。words 中任意一个子串中,每个字母都至多只出现一次。
如果通过以下操作之一,我们可以从 s1 的字母集合得到 s2 的字母集合,那么我们称这两个字符串为 关联的 :
- 往 s1 的字母集合中添加一个字母。
- 从 s1 的字母集合中删去一个字母。
- 将 s1 中的一个字母替换成另外任意一个字母(也可以替换为这个字母本身)。
数组 words 可以分为一个或者多个无交集的 组 。
一个字符串与一个组如果满足以下 任一 条件,它就属于这个组:
- 它与组内 至少 一个其他字符串关联。
- 它是这个组中 唯一 的字符串。
注意,你需要确保分好组后,一个组内的任一字符串与其他组的字符串都不关联。可以证明在这个条件下,分组方案是唯一的。
请你返回一个长度为 2 的数组 ans :
- ans[0] 是 words 分组后的 总组数 。
- ans[1] 是字符串数目最多的组所包含的字符串数目。
示例 1:
输入:words = ["a","b","ab","cde"]
输出:[2,3]
解释:
- words[0] 可以得到 words[1] (将 'a' 替换为 'b')和 words[2] (添加 'b')。所以 words[0] 与 words[1] 和 words[2] 关联。
- words[1] 可以得到 words[0] (将 'b' 替换为 'a')和 words[2] (添加 'a')。所以 words[1] 与 words[0] 和 words[2] 关联。
- words[2] 可以得到 words[0] (删去 'b')和 words[1] (删去 'a')。所以 words[2] 与 words[0] 和 words[1] 关联。
- words[3] 与 words 中其他字符串都不关联。
所以,words 可以分成 2 个组 ["a","b","ab"] 和 ["cde"] 。最大的组大小为 3 。示例 2:
输入:words = ["a","ab","abc"]
输出:[1,3]
解释:
- words[0] 与 words[1] 关联。
- words[1] 与 words[0] 和 words[2] 关联。
- words[2] 与 words[1] 关联。
由于所有字符串与其他字符串都关联,所以它们全部在同一个组内。
所以最大的组大小为 3 。提示:
1 <= words.length <= 2 * 10^4
1 <= words[i].length <= 26
words[i] 只包含小写英文字母。
words[i] 中每个字母最多只出现一次。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/groups-of-strings
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题
- 把单词26个字符是否出现作为 int 数的一个 bit 的 01 ,把字符串转成数字,并记录个数(有重复的字符串)
- 枚举 每个数字的 26 个位,使用题目给的3中规则进行变形,得到其他的数字,如果数字出现过,则这两个数字节点有一条无向边,构建图
- 图的遍历,找到连通块的数量,最大连通块的节点个数
class Solution {
public:vector<int> groupStrings(vector<string>& words) {unordered_map<int, unordered_set<int>> g;unordered_set<int> node;unordered_map<int, int> node_ct;for(auto& w : words){int num = 0;for(auto c : w)num |= 1<<(c-'a'); // 单词转26bit 数字node.insert(num); node_ct[num]++; // 有重复的,需要计数}for(auto num : node){for(int i = 0; i < 26; ++i){ // 遍历所有的 bitif((num>>i)&1) // i 位是 1{int othernum = num & ~(1<<i); // 删除i位if(node.find(othernum) != node.end()){g[num].insert(othernum);g[othernum].insert(num);}for(int j = 0; j < 26; ++j){ // 先删除一个1,再添加一个1,替换字母if(i==j || ((othernum>>j)&1)==1) continue;int anothernum = othernum | (1<<j);if(node.find(anothernum) != node.end()){g[num].insert(anothernum);g[anothernum].insert(num);}}}else // i 位是 0,可以添加一位1{int othernum = num | (1<<i); // 添加i位if(node.find(othernum) != node.end()){g[num].insert(othernum);g[othernum].insert(num);}}}}// 遍历图,找连通块的数量和最大的块的节点数量unordered_set<int> vis; // 访问过的点的集合int group = 0, ct = 0, maxct = 0;for(auto num : node){if(vis.find(num) != vis.end()) continue;group++;queue<int> q;q.push(num);vis.insert(num);ct = 0;while(!q.empty()){int tp = q.front();ct += node_ct[tp];q.pop();for(auto nt : g[tp]){if(vis.find(nt) != vis.end()) continue;q.push(nt);vis.insert(nt);}}maxct = max(maxct, ct);}return {group, maxct};}
};
1276 ms 199.5 MB C++
我的CSDN博客地址 https://michael.blog.csdn.net/
长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!