Skip to content

Latest commit

 

History

History
15 lines (9 loc) · 2.12 KB

File metadata and controls

15 lines (9 loc) · 2.12 KB

2157.Groups-of-Strings

本题明显是Union Find。暴力的方法就是将每个单词两两进行比较,如果满足三个条件之一,就可以将它们Union。判定的时候可以将字母集合用bit mask来表示,这样更方便。比如集合A添加一个字母等于B,就可以写成判断是否存在j,使得A+(1<<j)==B; 集合A删除一个字母等于B,就可以写成判断是否存在j,使得A-(1<<j)==B; 集合A替换一个字母等于B,就可以写成判断是否存在j和k,使得A-(1<<j)+(1<<k)==B.

比o(N^2)更高明的算法就是o(N*256).将所有的编码都存入一个集合。然后遍历每一个单词word[i]的编码A,查看以上三种操作的后果B是否存在于这个集合之中,是的话,就和编码B所对应的单词j给Union起来。注意,编码B可能对应着多个单词,但只需要将i与其中的一个单词(即家族代表)进行Union(因为编码相同的单词肯定已经Union起来了),否则这个方法本质等同于o(N^2).

但是本题有还有更好的o(N*26)的算法。事实上,本题中三个条件,其中第一个条件和第二个条件显然是等价的。我们依然可以用上述的方法,循环26次将每个单词的编码A扣掉一个1 bit得到B,将i与家族B的代表进行Union即可。

而第三个条件,本质也是如此。假设任意单词word[i]的编码A任意去掉一个字母,等于单词word[j]的编码C任意去掉一个字母,那么根据题意,i和j必须Union。那么这就意味着,我们将编码A的家族与它任意去掉一个字母后的编码B家族进行Union,其他单词也做类似的操作,就可以将满足条件三的任意一对单词必然会被Union起来。

所以本题的算法如下:

  1. 将每个单词i翻译成编码A,将i与编码A的家族进行Union。
  2. 将每个单词i的编码A,任意去掉一个字母变成编码B,将编码A的家族与B家族进行Union

满足以上操作之后,所有需要Union的单词一定已经做了归并。我们根据每个家族的族长进行分组统计,得到家族的数量和最大的家族。