题意:
题目意思简化:
给出n个只包含小写字母'a'~'z'的字符串,如果存在一个其他串是某个串的前缀,则舍弃掉,问剩余串的数量?
方法一:
直接模拟
思路:二重循环模拟,vis[i]初始值都为0,表示都未被舍弃。如果s[i]是s[j]的前缀,则舍弃掉s[j],将vis[j]赋值为1。
class Solution { public: int solve(int n, vector<string>& s) { int num=n;//num设为总数n vector<int> vis(n,0); for(int i=0;i<n;i++){ if(vis[i])//该字符串已被舍弃,跳过 continue; for(int j=0;j<n;j++){ if(i==j)//跳过自己与自己比较 continue; if(s[i]==s[j].substr(0,s[i].size())){//如果s[i]是s[j]的前缀,则舍弃掉s[j],将vis[j]赋值为1 vis[j]=1; num--;//数量减一 } } } return num; } };
时间复杂度:
空间复杂度:
方法二:
字典树
思路:
先将所有字符串插入,构造树。
再遍历每个字符串,到构建的树中查找。如果存在相同字符串或前缀,则舍弃该字符串。表示某字符串在树中的数量。
class Solution { public: int son[1000005][26],tail[1000005]; int id=0;//节点编号 int num=0; void insert(string str){//插入字符串 int now=0;//根节点编号为0 int num=str.size(); for(int i=0;i<num;i++){//遍历每个字符 int x=str[i]-'a'; if(son[now][x]==0)//如果不存在节点,则新建节点 son[now][x]=++id; now=son[now][x];//递归下去 } tail[now]++;//该字符串在树中的数量加一 } int query(string str){//判断str是否舍弃 int now=0;//根节点编号为0 int num=str.size(); for(int i=0;i<num;i++){ int x=str[i]-'a'; now=son[now][x]; //如果存在相同字符串或前缀,则舍弃该字符串 if((i==num-1&&tail[now]>1)||(i<num-1&&tail[now])){ return 1; } } return 0; } int solve(int n, vector<string>& s) { for(int i=0;i<n;i++){ insert(s[i]); } int num=0;//舍弃的数量 for(int i=0;i<n;i++){ num+=query(s[i]); } return n-num;//总的数量-舍弃数量=剩余数量 } };
时间复杂度:
空间复杂度: