题目描述:
给定一个字符串数组 arr,字符串 s 是将 arr 某一子序列字符串连接所得的字符串,如果 s 中的每一个字符都只出现过一次,那么它就是一个可行解。
请返回所有可行解 s 中最长长度。
示例 1:
输入:arr = [“un”,“iq”,“ue”]
输出:4
解释:所有可能的串联组合是 “”,“un”,“iq”,“ue”,“uniq” 和 “ique”,最大长度为 4。
示例 2:
输入:arr = [“cha”,“r”,“act”,“ers”]
输出:6
解释:可能的解答有 “chaers” 和 “acters”。
示例 3:
输入:arr = [“abcdefghijklmnopqrstuvwxyz”]
输出:26
提示:
1 <= arr.length <= 16
1 <= arr[i].length <= 26
arr[i] 中只含有小写英文字母
题目分析:
可以用dfs枚举每个pos, 对于每个pos来说, 又两种情况,选该字符或者不选该字符.
但是如何在dfs的时候记录当前的状态, 以至于可以快速的判断出有没有重复的字符呢?
答案是用掩码.
如果能想到这一点, 这个题就很容易解决啦~
void dfs(int idx, int result, int length, vector& arr)
dfs的参数解释:
idx 就是上面说的pos ,表示我们目前正在枚举的位的索引值.
result是当前字符串的掩码(mask).
length是当前字符串的长度.
arr是所有字符列表.
当时做的时候看到了这条提示,马上就ac了:
You can try all combinations and keep mask of characters you have.
ac代码:
class Solution {
public:
int mask[27];
int repeat[27];
int length;
int arr_size;
int maxx;
void dfs(int idx, int result, int length, vector<string>& arr) {
if (length > maxx)
maxx = length;
if (idx == arr_size)
return;
// 不选arr[idx]
dfs(idx + 1, result, length, arr);
// 选arr[idx]
// 先判断是否能选
// 首先判断他自己有没有重复.
if (repeat[idx])
return;
if ((result & mask[idx]) !=0) {
return;
}
// 判断完成, 可以选, 更新 result 和 length
result |= mask[idx];
length += arr[idx].size();
// cout << result << " " << length << endl;
dfs(idx + 1, result, length, arr);
return;
}
int maxLength(vector<string>& arr) {
int i, j;
int tmp1, tmp2;
memset(repeat, 0, sizeof(repeat));
for (i = 0; i < arr.size(); ++i) {
tmp1 = 0;
for (j = 0; j < arr[i].size(); ++j) {
tmp2 = 1 << (arr[i][j] - 'a');
if ((tmp1 & tmp2) != 0)
repeat[i] = 1;
tmp1 |= tmp2;
}
//cout << tmp << endl;
mask[i] = tmp1;
}
length = 0;
maxx = 0;
arr_size = arr.size();
dfs(0, 0, 0, arr);
return maxx;
}
};