字符串基础

Posted seaupnice

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串基础相关的知识,希望对你有一定的参考价值。

A - Ananagrams

题意:输入一定量的单词构成词典(区分大小写),从词典中找出符合条件的单词,条件:单词转换成小写字母排序后与词典其他经此操作的单词不同(描述有点乱)。

Thinking:

这个题我最开始的感觉是构造hash函数来判重,然后并没有构造(查到)可以操作的函数,再然后就不会做了。网上给出了STL的方法,vector,map和string的排序,很好的解决了这道题的需要。

还有就是题目所说的lexicographic (case-sensitive) order 应该记下这个定义,这是集合和序的知识,虽然在这里只是基于ASCII排序即可。

 

技术分享图片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <vector>
 4 #include <algorithm>
 5 #include <map>
 6 #include <cctype>
 7 #include <string>
 8 #include <algorithm>
 9 using namespace std;
10 vector<string> v;
11 map<string, int> m;
12 string getlow(const string &x){
13     string tmp = x;
14     for(int i=0; i<tmp.size(); i++){
15         tmp[i] = tolower(tmp[i]);
16     }
17     sort(tmp.begin(), tmp.end());
18     return tmp;
19 }
20 int main(){
21 //    freopen("in.txt", "r", stdin);
22     string s;
23     while(cin >> s){
24         if(s[0] == #)break;
25         v.push_back(s);
26         string tmp = getlow(s);
27         if(m.count(tmp)==0) m[tmp]=0;
28         m[tmp]++;
29     }
30     vector<string> ans;
31     for(int i=0; i<v.size(); i++){
32         if(m[getlow(v[i])] == 1){
33             ans.push_back(v[i]);
34         //    cout << v[i] << " ------" << endl;
35         }
36     }
37     sort(ans.begin(), ans.end());
38     for(int i=0; i<ans.size(); i++){
39         cout << ans[i] << endl;
40     }
41     return 0;
42 }
View Code

 

C - Number Sequence

这个KMP(求位置)太明显了,不说了。

技术分享图片
 1 #include <cstdio>
 2 #include <string>
 3 #include <cctype>
 4 using namespace std;
 5 const int maxp = 10010, maxt = 1e6+10;
 6 int f[maxp];
 7 int P[maxp], T[maxt];
 8 void getnext(int lenp){
 9     f[0] = f[1] = 0;
10     for(int i=1; i<lenp; i++){
11         int j = f[i];
12         while(j && P[i]!=P[j])  j=f[j];
13         f[i+1] = P[i]==P[j]? j+1 : 0;
14     }
15 }
16 int kmp(int n, int m){
17     int cnt = 0, j = 0;
18     for(int i=0; i<n; i++){
19         while(j && P[j]!=T[i]){
20             j = f[j];
21         }
22         if(P[j] == T[i])  j++;
23         if(j == m)  return i-m+1+1; //cnt++
24     }
25     return -1;
26 }
27 int main(){
28 //    freopen("in.txt", "r", stdin);
29     int tt;
30     scanf("%d", &tt);
31     while(tt--){
32         int n, m;
33         scanf("%d%d", &n, &m);
34         for(int i=0; i<n; i++){
35             scanf("%d", &T[i]);
36         }
37         for(int i=0; i<m; i++){
38             scanf("%d", &P[i]);
39         }
40         getnext(m);
41         printf("%d
", kmp(n, m));
42     }
43     return 0;
44 }
View Code

 

D - Oulipo 

这个KMP(计数)太明显了,不说了。

技术分享图片
 1 #include <cstdio>
 2 #include <string>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <iostream>
 6 using namespace std;
 7 char p[10010], t[1000010];
 8 int f[10010];
 9 void getnext(){
10     int m = strlen(p);
11     f[0]=f[1] = 0;
12     for(int i=1; i<m; i++){
13         int j=f[i];
14         while(j && p[i]!=p[j]) j=f[j];
15         f[i+1] = p[i]==p[j]?j+1:0;
16     }
17 }
18 int kmp(){
19     int n = strlen(t), m =strlen(p);
20     int cnt=0, j=0;
21     for(int i=0; i<n; i++){
22         while(j && p[j]!=t[i]) j=f[j];
23         if(p[j]==t[i]) j++;
24         if(j==m) cnt++;
25     }
26     return cnt;
27 }
28 void show()
29 {
30     int m=strlen(p);
31     for(int i=0;i<=m;i++) printf("%4c",p[i]);
32     putchar(
);
33     for(int i=0;i<=m;i++) printf("%4d",f[i]);
34     putchar(
);
35 }
36 int main(){
37 //    freopen("in.txt", "r", stdin);
38     int tt;
39     scanf("%d", &tt);
40     while(tt--){
41         scanf("%s", p);
42         getnext();
43         scanf("%s", t);
44         printf("%d
", kmp());
45     }
46     return 0;
47 } 
View Code

 

E - Theme Section

题意:

有种音乐,音乐用M(10^6)个小写字母表示,主旋律为E,音乐形如EAEBE,计算主旋律E最长可以多长。

Thinking:

这道题数据应该是有问题的,我的1A解法肯定是错误的

题目很好理解,看到这个形式熟悉的EAEBE,以及最长,就想当然的以为是求最大的前后缀匹配(感觉自己脑子有点简单),然后就开始讨论情况,按长度分为两种,然后就谜之默认了中间的E不存在,然后胡搞了下,竟然AC了,开始很高兴,后来去厕所回来的过程中想到了这个中间的E如果小于前后缀匹配的最大值怎么办?

然后回来构造了个样例 aacsdafrtaa ,果然程序运行的答案错了。

 

下面贴出错误code

技术分享图片
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 using namespace std;
 8 const int maxn = 1e6+10;
 9 char str[maxn];
10 int f[maxn];
11 void getnext(int m){
12     f[0] = f[1] = 0;
13     for(int i=1; i<m; i++){
14         int j = f[i];
15         while(j && str[i]!=str[j]) j=f[j];
16         f[i+1] = str[i]==str[j]?j+1:0;
17     }
18 }
19 int main(){
20 //    freopen("in.txt", "r", stdin);
21     int n;
22     scanf("%d", &n);
23     while(n--){
24         scanf("%s", str);
25         int m = strlen(str);
26         if(m<=2){
27             printf("0
");
28         }else{
29             getnext(m);
30             int tmp = min((int)ceil(m/2.0)-1, f[m]);
31             //cout << "ceil(m/2) = " << ceil(m/2.0) << endl;
32             printf("%d
", tmp);
33         }
34     }
35     return 0;
36 }
37 /*
38  aacsdafrtaa
39 */
View Code

教训是:思考问题不全面,总想以偷懒的方法做题。

 

下面思考正解,其实相比上面的思考,只差一个要解决的问题就是中间的E:沿着next数组,找到字符串非前缀后缀的中间那段是否出现前缀(后缀),这个过程是一个kmp的过程,只要找到即可退出枚举,因为这是沿着next走,即保证长度由大到小。

技术分享图片
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 using namespace std;
 8 const int maxn = 1e6+10;
 9 char str[maxn];
10 int f[maxn];
11 bool vis[maxn];
12 void getnext(int m){
13     f[0]=-1;
14     for(int i=1, j=-1; i<m; i++){
15         while(j>=0 && str[i]!=str[j+1])  j=f[j];
16         if(str[j+1]==str[i]) j++;
17         f[i] = j;
18     }
19 }
20 int kmp(int n, int m){
21     //n:母串长 从[m-1,n-m] kmp子串 
22     for(int i=m-1, j=-1; i<n-m; i++){
23         while(j>=0 && str[j+1]!=str[i]) j=f[j];
24         if(str[j+1]==str[i]) j++;
25         if(j+1 == m)  return m;
26     }
27     return -1;
28 }
29 int main(){
30     freopen("in.txt", "r", stdin);
31     int n;
32     scanf("%d", &n);
33     while(n--){
34         scanf("%s", str);
35         int m = strlen(str);
36         if(m<=2){
37             printf("0
");
38         }else{
39             getnext(m);
40             /*
41             for(int i=1; i<=m; i++){
42                 cout << f[i] << "    ";
43             }
44             cout << endl;
45             */
46             int j = m-1, tmp=-1;
47             while(f[j] >= 0){
48                 int len = kmp(m, f[j]+1);
49                 if(len > tmp){
50                     tmp = len;
51                     break;
52                 }
53                 j = f[j];
54             }
55             if(tmp==-1) printf("0
");
56             else  printf("%d
", tmp);
57         }
58     }
59     return 0;
60 }
View Code

 

F - Cyclic Nacklace

题意:题目废话太多,直接从The charmbracelet is made up with那里开始看。向一个字符串加多少字符可以保证全部字符串至少循环2次。

Thinking:

next数组找到最大前后缀匹配后即得到循环前缀,然后判断是否已经自循环多次,是否只有一个珍珠(字符),这些情况不用加字符;剩下的情况则通过取余操作去掉一个循环节,即得到剩下存在的字符,即可知要加的字符数。

技术分享图片
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <string>
 6 #include <algorithm>
 7 using namespace std;
 8 
 9 const int maxn = 100005;
10 char str[maxn];
11 int f[maxn];
12 
13 void getnext(int m){
14     f[0] = f[1] = 0;
15     for(int i=1; i<m; i++){
16         int j = f[i];
17         while(j && str[i]!=str[j]){
18             j = f[j];
19         }
20         f[i+1] = str[i]==str[j]?j+1:0;
21     }
22 }
23 int main(){
24 //    freopen("in.txt", "r", stdin);
25     int tt;
26     scanf("%d", &tt);
27     while(tt--){
28         scanf("%s", str);
29         int m = strlen(str);
30         getnext(m);
31         /*
32         for(int i=1; i<=m; i++){
33             cout << f[i] << "    ";
34         }
35         cout << endl;
36         */
37         int tmp = m - f[m];
38         if(m != tmp && m % tmp==0){
39             printf("0
");
40         }else{
41             printf("%d
", tmp - f[m]%tmp);
42         }
43     }
44     return 0;
45 }
View Code

 

B - Always an integer

题意:给定一个形如P/D(P:n的整系数多项式,D是正整数)的多项式,判断它是否在所有正整数处取到整数值。

这题没做出来,记录下学习心得:

这里先记一个结论:一个整系数多项式P总是正整数D的倍数的判断依据:把n=1,2,……k+1带入试一遍即可,k是多项式中最高项的次数。

这里证明训练指南124页很详细,数学归纳+查分数列推出。

本题还有难点在于字符串的处理,知道数学结论后,写了好久,怎么都写不对。这里参考了一些博客,找到了一种比较好理解的方法,就是通过结构体保存 系数 和 阶数,然后通过字符‘n’和字符‘/‘将数据分为三类:系数,阶数,除数。得到这些数据后,就利用结论写就好了。

技术分享图片
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <map>
 5 #include <string>
 6 #include <cctype>
 7 using namespace std;
 8 #define LL long long
 9 struct D{
10     LL x, k;
11 }d[110]; 
12 int cnt;
13 LL mu, maxk;
14 /*
15  * 模拟时数字和符号分开处理,符号根据情况也分开处理,可以多用参数标记上回合运算的一些情况,并正确更新参数 
16 */
17 void build(const string &str){
18     maxk = mu = 0;
19     cnt = 0;
20     LL s=0, a=0, b=0, flag = 1;
21     int len = str.size();
22     for(int i=0; i<len; i++){
23         if(str[i]>=0 && str[i]<=9){
24             if(s==0){  // n^符号前的数字 
25                 a = a*10 + (str[i]-0);
26             }else if(s==1){ // n^符号后的数字 
27                 b = b*10 + (str[i]-0);
28             }else if(s==2){  //除号后的数字 
29                 mu = mu*10 + (str[i]-0);
30             }
31         }else if(str[i]==/){
32             s = 2;
33         }else if(str[i] == n){
34             s = 1;
35         }else if(str[i]==) || str[i]==+ || str[i]==-){
36             if(s >= 1){
37                 if(a==0) a=1;
38                 if(b==0) b=1;
39             }
40             maxk=max(maxk, b);  //保存最大的阶 
41             d[cnt].x = a * flag;     // k阶对应的系数 
42             d[cnt].k = b;            // k阶对应的指数 
43             cnt++;
44             if(str[i]==-){
45                 flag = -1;
46             }else if(str[i]==+){
47                 flag = 1;
48             }
49             a=b=s=0;
50         }
51     }
52 }
53 LL pow_(LL a, LL b){
54     LL ans = 1;
55     while(b){
56         if(b&1){
57             ans = ans * a % mu;
58         }
59         b >>= 1;
60         a = a * a % mu;
61     }
62     return ans;
63 }
64 bool solve(){
65     for(LL i=1; i<=maxk+1; i++){
66         LL ans = 0;
67         for(int j=0; j<cnt; j++){
68             ans = (ans + d[j].x * pow_(i, d[j].k)) % mu;
69         }
70         if(ans != 0)    return false;
71     }
72     return true;
73 }
74 int main(){
75 //    freopen("in.txt", "r", stdin);
76     string s;
77     int tt = 0;
78     while(cin >> s){
79         //cout << s << endl;
80         if(s == ".")break;
81         build(s);
82         printf("Case %d: %s
", ++tt, solve()?"Always an integer":"Not always an integer");
83     }
84     return 0;
85 }
View Code

 

还有很多内容,待补。

以上是关于字符串基础的主要内容,如果未能解决你的问题,请参考以下文章

逆向及Bof基础实践

20155307刘浩《网络对抗》逆向及Bof基础

20155311高梓云《网络对抗》逆向及Bof基础

20145301赵嘉鑫《网络对抗》逆向及Bof基础

[vscode]--HTML代码片段(基础版,reactvuejquery)

[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础