题目描述
给定字符串列表 strs ,返回其中 最长的特殊序列 。如果最长特殊序列不存在,返回 -1 。
特殊序列 定义如下:该序列为某字符串 独有的子序列(即不能是其他字符串的子序列)。
s 的 子序列可以通过删去字符串 s 中的某些字符实现。
例如,“abc” 是 “aebdc” 的子序列,因为您可以删除"aebdc"中的下划线字符来得到 “abc” 。“aebdc"的子序列还包括"aebdc”、 “aeb” 和 “” (空字符串)。
示例 1:
输入: strs = [“aba”,“cdc”,“eae”]
输出: 3
示例 2:
输入: strs = [“aaa”,“aaa”,“aa”]
输出: -1
提示:
2 <= strs.length <= 50
1 <= strs[i].length <= 10
strs[i] 只包含小写英文字母
分析
这题还是有点意思的,知道性质的话很快能做出来,不知道性质的话就只能暴力枚举了,而暴力枚举也需要技巧,下面分别用暴力枚举算法和更高效的算法求解本题。
方法一
既然要求最长特殊子序列,那么我们就先枚举下所有的子序列,然后判断下这个子序列出现在了几个字符串中,统计下只出现在一个字符串中的子序列也就是特殊序列的最大长度。每个字符串长度不超过10,子序列的数量也就是210,最多50个子序列,总的子序列数量不过是5w级别的,所有暴力枚举完全没有问题。
第一个问题,如何枚举子序列,当前是使用二进制表示来枚举,之前周赛题解里也提到过。
vector<string> v(1<<n);
unordered_set<string> us;
for(int k = 0;k < n;k++){
for(int j = 0;j < 1 << k;j++){
v[j|1<<k] = x[k] + v[j];
us.insert(v[j|1<<k]);
}
}
通过自低位向高位逐位添加1的方式来枚举子序列,并且将子序列添加到set里去重,因为一个子序列可以在同一个字符串里重复出现,为了防止后面统计子序列出现次数时重复统计,所以去下重。
之后直接放进map里增加计数即可,最终在map里出现次数是1的子序列就是特殊序列,使用他们的长度更新解即可,有一点需要注意,更新解的时候res的初值是-1,如果直接使用size与-1比较,得到的永远是size < -1,因为STL容器的size()函数的返回值是unsigned类型,与有符合类型数比较会统一转化为无符号数,而-1转化为无符号是11111…,自然大于所有的size。所以需要先将size转化为int类型再进行比较。
暴力枚举的代码如下:
class Solution {
public:
unordered_map<string,int> m;
int findLUSlength(vector<string>& strs) {
int res = -1;
for(int i = 0;i < strs.size();i++){
string &x = strs[i];
int n = x.size();
vector<string> v(1<<n);
unordered_set<string> us;
for(int k = 0;k < n;k++){
for(int j = 0;j < 1 << k;j++){
v[j|1<<k] = x[k] + v[j];
us.insert(v[j|1<<k]);
}
}
for(auto t : us) m[t]++;
}
for(auto &[x,y] : m){
int n = x.size();
if(y == 1 && n > res) res = x.size();
}
return res;
}
};
方法二
我们在学习线性代数中的向量的线性相关时,有个性质是如果两个向量a和b线性无关,那么增加它们的维度得到的向量组也是线性无关的。比如(1,0)和(0,1)线性无关,增加一维得到(1,0,1),(0,1,1)也是线性无关的。本题也是一样,如果一个字符串里存在特殊序列,也就是字符串的某个子序列都不是其他字符串的子序列,那么我们增加这个子序列的长度自然也不会是其他字符串的子序列了,也就说,如果一个字符串中存在特殊序列,那么这个字符串本身就是特殊序列。
因此这题我们只需要枚举每个字符串,判断下它是不是其他字符串的子序列即可。如果是判断子串可以直接使用string里的find函数,判断子序列就要自己使用双指针比较了,还是比较简单的。
class Solution {
public:
int findLUSlength(vector<string>& strs) {
int res = -1,n = strs.size();
for(int i = 0;i < n;i++){
string &x = strs[i];
bool flag = true;
for(int j = 0;j < n;j++){
if(j == i) continue;
string &y = strs[j];
if(x.size() <= y.size()) {
int p = 0,q = 0;
while(p < x.size() && q < y.size()){
if(x[p] == y[q]) p++,q++;
else q++;
}
if(p == x.size()){
flag = false;
break;
}
}
}
if(flag) res = max(res,(int)x.size());
}
return res;
}
};