终曲 HDU - 2572 时间限制1000ms 内存限制128MB
问题大意:
给定三个字符串s,s1,s2,要求求出s中包含s1和s2的最短子串。
这道题我是用了分两步的方法去做的。首先求出$s$中包括$s_1$和$s_2$的子串,然后输出其最短的。我这里直接使用了标准库的string类的find()方法,依次查找到$s_1$和$s_2$的起始位置为$p_1$、$p_2$,那么事实上就可以确定一个子串了($s_1[min(p_1,p_2)..(max(p_1,p_2)+len)]$,其中$len$是$s_1$,$s_2$中出现在后面的串的长度)。这里有一点需要注意的是,这种方法并不能完全确定所有的子串,因为假如在$p_2$之后同样出现了和$s_2$相同的串,则从$p_1$到$p_3+length$同样也是$s_2$的子串。如果要求出所有的子串,就应该使用双指针查找的方式。好在题目要求只需要输出其最短的,而$p_3>max(p_1,p_2)$显然成立,因此这些串显然更长,不符合要求,自然可以排除掉。这样求出一个子串之后,把他放进优先队列pq里,而后将s利用substr()方法进行截取(从$min(p_1,p_2)$之后到原字符串末尾),再进行如此迭代操作,直到找不到目标子串为止。这样输出优先队列的top元素即为答案。当然这里利用vector容器然后调用sort()函数也是可以的。更简洁的做法,便是每捕捉到一个子串就进行比较,保留其中最短的。
主要需要提及一下,priority_queue容器需要指定比较大小的方式,对于有特殊比较需求,应该重载类的比较运算符<或者自定义一个仿函数。在C++ STL中,仿函数就是一个类(或者结构体),重载了其“()”运算符,使之看起来更像一个函数调用。这里就自定义了一个仿函数mylesscmp,用来对子串进行比较,以便于输出。如果不自定义这个仿函数,他会自动调用string的operator<进行比较,与题目要求就不一致了。
1 #include<iostream> 2 #include<string> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 struct mylesscmp 7 { 8 bool operator() (string a, string b) 9 { 10 if (a.length() < b.length()) 11 return false; 12 if (a.length() > b.length()) 13 return true; 14 else 15 return (a > b); 16 } 17 }; 18 int main() 19 { 20 string src, sub1, sub2; 21 int T; 22 cin >> T; 23 while (T--) 24 { 25 priority_queue<string, vector<string>, mylesscmp> pq; 26 cin >> src >> sub1 >> sub2; 27 int pos1, pos2; 28 while (1) 29 { 30 pos1 = src.find(sub1, 0); 31 pos2 = src.find(sub2, 0); 32 if (pos1 == -1 || pos2 == -1) 33 break; 34 int mn, len; 35 if (pos1 > pos2) 36 { 37 mn = pos2; 38 len = pos1 - pos2 + sub1.length(); 39 } 40 else 41 { 42 mn = pos1; 43 len = pos2 - pos1 + sub2.length(); 44 } 45 pq.push(src.substr(mn, len)); 46 src = src.substr(mn + 1, src.length() - mn - 1); 47 } 48 if (pq.empty()) 49 cout << "No" << endl; 50 else 51 cout << pq.top() << endl; 52 } 53 return 0; 54 }