给定一个字符串数组 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]
中只含有小写英文字母
分析
这是一道回溯题,可以从头到尾遍历,维护一个当前选择的字符串字符的一个map,由于只有26个字符,所以这个map可以使用int的二进制位移方式代替,两种情况,选择当前字符串还是不选择当前字符串,如果不选择当前字符串,那返回值就等于从下一个节点开始计算的结果,如果选择当前字符串并且当前字符串符合可行解s的条件,那还需要更新map,结果为更新map后下一个节点计算后的值+当前字符串的长度,最后取两个分支(选择还是不选择)较大的值作为函数返回值。
代码
class Solution {
public:
int a = 0;
bool UniqueWhenAddStr(string &str) {
for (auto c : str) {
if (a & (1 << (c-'a'))) {
return false;
}
}
return true;
}
void AddStr(string &str) {
for (auto c : str) {
a = a | (1 << (c-'a'));
}
}
void RemoveStr(string &str) {
for (auto c : str) {
a = a ^ (1 << (c-'a'));
}
}
bool uniqueStr(string &str) {
int b = 0;
for (auto c : str) {
if (b & (1 << (c-'a'))) {
return false;
} else {
b = b | (1 << (c-'a'));
}
}
return true;
}
int dfs(vector<string> &arr, int index) {
if (arr.size() == index) return 0;
int value = dfs(arr, index+1);
if (uniqueStr(arr[index]) && UniqueWhenAddStr(arr[index])) {
AddStr(arr[index]);
int k = dfs(arr, index+1) + arr[index].size();
int tem = std::max(k, value);
RemoveStr(arr[index]);
return tem;
}
return value;
}
int maxLength(vector<string>& arr) {
return dfs(arr, 0);
}
};
代码精进之路
代码精进之路,我们一起成长!