难度:中等。
标签:位运算,回溯算法。
想到了回溯,使用回溯算法无任何剪枝代码如下,注意需要判断每个字符串中的字符是否重复。
正确解法:
class Solution {
int max_len = 0;
void dfs(vector<string> arr, int* a, int k, int len){
if(k >= arr.size()){
if(len > max_len)max_len = len;
return;
}
int str_len = arr[k].length();
bool flag = true;
// 使用temp判断第k个字符串中是否有重复字符
int temp[27] = {0};
for(int i = 0; i < str_len; ++i){
int c = arr[k][i] - 'a';
if(a[c] == 1 || temp[c] == 1){
flag = false;
break;
}
temp[c] = 1;
}
if(flag){
for(int i = 0; i < str_len; ++i){
a[arr[k][i] -'a'] = 1;
}
dfs(arr, a, k + 1, len + str_len);
for(int i = 0; i < str_len; ++i){
a[arr[k][i] -'a'] = 0;
}
}
dfs(arr, a, k + 1, len);
}
public:
int maxLength(vector<string>& arr) {
int n = arr.size();
int a[27] = {0};
dfs(arr, a, 0, 0);
return max_len;
}
};
结果:
加上剪枝,对按照字符串的长度从长到短进行排列。使用数组rest_len存储当前字符及其后字符的长度总和,参考rest_len进行剪枝。
正确解法:
class Solution {
int max_len = 0;
vector<int> rest_len;
void dfs(vector<string> arr, int* a, int k, int len){
if(k >= arr.size()){
if(len > max_len)max_len = len;
return;
}
// 剪枝
if(rest_len[k] + len <= max_len)return;
int str_len = arr[k].length();
bool flag = true;
int temp[27] = {0};
for(int i = 0; i < str_len; ++i){
int c = arr[k][i] - 'a';
if(a[c] == 1 || temp[c] == 1){
flag = false;
break;
}
temp[c] = 1;
}
if(flag){
for(int i = 0; i < str_len; ++i){
a[arr[k][i] -'a'] = 1;
}
dfs(arr, a, k + 1, len + str_len);
for(int i = 0; i < str_len; ++i){
a[arr[k][i] -'a'] = 0;
}
}
dfs(arr, a, k + 1, len);
}
static bool cmp(string& a, string& b){return a.length()>b.length();}
public:
int maxLength(vector<string>& arr) {
int n = arr.size();
sort(arr.begin(), arr.end(), cmp);
rest_len.resize(n, 0);
rest_len[n - 1] = arr[n - 1].length();
for(int i = n - 2; i >= 0; --i){
rest_len[i] = rest_len[i + 1] + arr[i].length();
}
int a[27] = {0};
dfs(arr, a, 0, 0);
return max_len;
}
};
结果:
使用位运算可以进一步优化,位运算的方法我怎么也学不会!!!放弃。。。