思路
这道题维护一个集合 Set,从索引0开始遍历,每次遍历判断集合里的每个 String 和当前的字符串 arr[i] 能否组成新的无重复字符的字符串,若能,添加到一个临时集合中。每一次遍历后,要将这个临时集合添加到总集合 Set 中,并把当前字符串 arr[i] 也添加到 Set 中,以便下一次的遍历。
一些细节
位图
为了简单表示两个字符串是否有重复,考虑到只有小写字母,我们用一个 int 变量来替换每一个字符串。‘a’ 映射到倒数第一位,‘b’映射到倒数第二位…依此推论
所以,字符串映射到整数的函数如下:
public int getMap(String s){
int ans = 0;
for(int i=0;i<s.length();i++){
int tmp = 1 << (s.charAt(i)-'a');
if((ans & tmp)!=0){
return 0;
}
ans |= tmp;
}
return ans;
}
要注意的是,如果 ans & tmp 不为 0,说明这个字符串中有重复的字母,直接返回 0,代表不要用这个字符串。
统计字符串中字符的个数
由于我们把字符串映射到了一个整数上,就要有一个判断总的字符个数的函数。
public int cal(int i){
int ans = 0;
while(i>0){
i = i&(i-1);
ans++;
}
return ans;
}
主要解释一下 i & (i-1) 的意思。这个操作把 i 最后的二进制位为 1 的地方变成了 0 。
主程序
做好了以上准备后,我们就直接遍历就行了。。。注意如果 map[i]为0,说明此时的字符串有重复数,不满足要求,直接跳过就好。
class Solution {
public int maxLength(List<String> arr) {
int res = 0;
int[] map = new int[arr.size()];
for(int i=0;i<arr.size();i++){
map[i]=getMap(arr.get(i));
}
Set<Integer> set = new HashSet<>();
for(int i=0;i<map.length;i++){
if(map[i]==0){
continue;
}
Set<Integer> settmp = new HashSet<>();
for(int j: set){
if((map[i]&j)==0){
settmp.add(map[i]|j);
}
}
set.add(map[i]);
set.addAll(settmp);
}
for(int i: set){
res = Math.max(res, cal(i));
}
return res;
}
public int getMap(String s){
int ans = 0;
for(int i=0;i<s.length();i++){
int tmp = 1 << (s.charAt(i)-'a');
if((ans & tmp)!=0){
return 0;
}
ans |= tmp;
}
return ans;
}
public int cal(int i){
int ans = 0;
while(i>0){
i = i&(i-1);
ans++;
}
return ans;
}
}