我已经解决了以下问题,但仍然需要提高性能:
我有N个字。对于每个有效的i,单词i由一个 字符串Di仅包含小写的元音,即字符“ a”,“ e”, 'i','o','u'。
(无序)单词对的总数是多少,例如 连接在一起,它们包含所有元音吗?
我的C ++代码使用位数组来表示单词中存在的元音。然后,我通过组合它们的位数组来检查所有字符串对,以查看是否设置了所有元音位。我通过将组合与位数组“ complete”进行比较来做到这一点,该数组具有与元音相对应的所有位:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t; // number of different test cases
while(t--)
{
int n; // number of strings
cin>>n;
int con_s[n];
for(int i=0;i<n;i++)
{
string s;
cin>>s;
con_s[i]=0; // converting vowels present in string into a bit array
for(int j=0;j<s.length();j++)
{
con_s[i] = con_s[i] | (1<<(s[j]-'a'));
}
}
int complete = 0; // bit array corresponding to all possible vowels
complete = (1<<('a'-'a')) | (1<<('e'-'a')) | (1<<('i'-'a')) | (1<<('o'-'a')) | (1<<('u'-'a'));
// cout<<complete;
int count = 0;
for(int i=0;i<n-1;i++) // check the pairs
{
for(int j=i+1;j<n;j++)
{
if((con_s[i] | con_s[j])==complete)count++;
}
}
cout<<count<<"\n";
}
return 0;
}
尽管位数组使用了非常快的位操作,但是当输入字符串集更大时,我的算法似乎效率不够。谁能建议一个有效的解决方案?
其他信息
测试用例:
Input:
1
3
aaooaoaooa
uiieieiieieuuu
aeioooeeiiaiei
Result: 2
说明: 2对(1和2)和(2和3)串联时包含所有5个元音,而对(1和3)不匹配条件,因为串联不包含'u'。因此结果是2。
约束:
1≤T≤1,000
1≤N≤105
1≤|Di|≤1,000 for each valid i
the sum of all |D_i| over all test cases does not exceed 3⋅107
答案 0 :(得分:0)
假设您有很多字符串。您的算法将比较它们之间的所有字符串,这就是可怕的迭代次数。
构建一个映射,将一串有序的唯一元音(例如“ ae”)与找到的包含这些唯一元音的所有字符串的列表相关联,无论重复的次数和顺序如何。例如:
ao -> aaooaoaooa, aoa, aaooaaooooooo (3 words)
uie -> uiieieiieieuuu, uuuuiiiieeee (2 words)
aeio -> aeioooeeiiaiei (1 word)
当然,有很多字符串,因此在代码中,您将使用位图而不是有序唯一元音的字符串。还要注意,您不想生成组合字符串的列表,而只想生成它们的计数。因此,您不需要所有字符串事件列表,只需维护与位图匹配的字符串数即可:
16385 -> 3
1048848 -> 2
16657 -> 1
然后像您一样查看映射现有索引之间的获胜组合。对于较大的字符串列表,您将具有较小的映射索引列表,因此这将是一项重大改进。
对于每个获胜组合,将第一个字符串列表的大小乘以第二个字符串列表的大小,以增加计数。
16385 1048848 is complete -> 3 x 2 = 6 combinations
1048848 16657 is complete -> 2 x 1 = 2 combinations
---
8 potential combinations
这些组合是通过分析3x2位图而不是查看对应于唯一字符串的6x5位图找到的。如果您拥有更多的弦,则增益会显着提高。
更笼统地说,由于您有5个窝并且必须至少有一个窝,所以最多只能有2<<5-1
个,所以31个不同的位图也就是最多C(31,2),即465 组合,用于检查输入的字符串是100还是1000万。我说它大约为O(n)正确吗? 31*30
是930
可能的实现:
map<int, int> mymap;
int n;
cin>>n;
for(int i=0;i<n;i++) {
string s;
cin>>s;
int bm=0;
for(int j=0;j<s.length();j++)
bm |= (1<<(s[j]-'a'));
mymap[bm]++;
}
int complete = (1<<('a'-'a')) | (1<<('e'-'a')) | (1<<('i'-'a')) | (1<<('o'-'a')) | (1<<('u'-'a'));
int count = 0;
int comparisons = 0;
for (auto i=mymap.begin(); i!=mymap.end(); i++) {
auto j=i;
for(++j;j!=mymap.end();j++) {
comparisons++;
if((i->first | j->first)==complete) {
count += i->second * j->second;
cout << i->first <<" "<<j->first<<" :"<<i->second<<" "<<j->second<<endl;
}
}
}
auto special = mymap.find(complete); // special case: all strings having all letters
if (special!=mymap.end()) { // can be combined with themselves as well
count += special->second * (special->second -1) / 2;
}
cout<<"Result: "<<count<<" (found in "<<comparisons<<" comparisons)\n";
Online demo with 4 examples(仅包含所有字母的字符串,您的初始示例,上面的示例以及包含多个其他字符串的示例)