第四章小结
大战1-8
没错,天梯赛让我自闭的题目,终于ac了。在天梯赛,我的思想是把空格,问号,i和me与大小写处理好,然后将句子的每一个单词放入一个二维数组,然后就很容易用cmp比较can you和could you了。在比赛后我仍使用这思想,敲出来了:
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 char ans[1000][1000],a[10000];//ans是答案数组,a用于读入 5 int vis[1000];//用于标记分隔符前面的空格 6 int k,hang;//中间变量 7 int main() 8 { 9 int n; 10 cin>>n; 11 getchar(); 12 while(n--) 13 { 14 memset(ans,-1,sizeof(ans)); 15 memset(vis,0,sizeof(vis)); 16 cin.getline(a,1000); 17 cout<<a<<endl<<"AI: "; 18 int h=strlen(a); 19 20 for(int i=0;i<h;i++) 21 { 22 if(a[i]=='?') 23 { 24 a[i]='!'; 25 } 26 else if(isupper(a[i])&&a[i]!='I')//是大写字母而且不是大写i 27 { 28 a[i]=tolower(a[i]);//变成大写 29 } 30 31 } 32 33 k=0,hang=0; 34 35 for(int i=0;i<h;) 36 { 37 char fuzhi[100];//中间变量,用于复制进ans数组 38 k=0; 39 40 if( isalpha(a[i]) )//是字母,意味着单词出现了 41 { 42 while( i<h && isalpha(a[i]) )//读入单词 43 { 44 fuzhi[k++]=a[i++]; 45 } 46 } 47 48 else if( isdigit(a[i]) )//读入数字 49 { 50 while( i<h && isdigit(a[i]) ) 51 { 52 fuzhi[k++]=a[i++]; 53 54 } 55 56 } 57 else if(a[i]==' ')//是空格,就把后面多于的空格消掉 58 { 59 60 fuzhi[k++]=' '; 61 while( i<h && a[i]==' ' ) 62 i++; 63 } 64 65 else 66 {//是分隔符,就得看看前面有没有空格,有的话就标记vis【前面一行】 67 fuzhi[k++]=a[i++]; 68 if( hang>0 && strcmp(ans[hang-1]," ")==0) 69 { 70 vis[hang-1]=-1; 71 } 72 } 73 74 fuzhi[k]='\0'; 75 if( strcmp(fuzhi," ")==0 && ( i==h || hang==0) )//如果是首尾空格,就继续 76 { 77 continue; 78 } 79 //cout<<"复制为"<<fuzhi<<"此时i为"<<i<<endl; 80 strcpy(ans[hang++],fuzhi);//把东西装进ans数组,然后hang++,继续循环 81 82 } 83 84 for(int i=0;i<hang;i++) 85 { 86 if(strcmp(ans[i],"I")==0||strcmp(ans[i],"me")==0) 87 strcpy(ans[i],"you"); 88 else if(strcmp(ans[i],"could")==0) 89 { 90 int z=i+1; 91 while(vis[z]==-1)//负一就无视 92 z++; 93 z=z+1;//第一个不是负一的,此时要看看它后面有没有负一 94 if(vis[z+1]==-1) 95 { 96 z=z+1; 97 while(vis[z]==-1) 98 z++; 99 } 100 if(strcmp(ans[z],"you")==0) 101 { 102 strcpy(ans[i],"I"); 103 strcpy(ans[z],"could"); 104 } 105 } 106 else if(strcmp(ans[i],"can")==0)//同上 107 { 108 109 int z=i+1; 110 while(vis[z]==-1) 111 z++; 112 z=z+1; 113 if(vis[z]==-1) 114 { 115 z=z+1; 116 while(vis[z]==-1) 117 z++; 118 } 119 if(strcmp(ans[z],"you")==0) 120 { 121 strcpy(ans[i],"I"); 122 strcpy(ans[z],"can"); 123 } 124 } 125 } 126 for(int i=0;i<hang;i++) 127 { 128 if(vis[i]==-1) 129 continue; 130 cout<<ans[i]; 131 } 132 cout<<endl; 133 } 134 return 0; 135 }
但是,过了四个测试点,还有两个段错误,一直debug不出来。老师的方法是对原串进行预处理,把空格,大小写什么的先弄了,最后遍历,判断can(could) you,匹配的时候不改变原串输出i can i could,这样就可以不改变原串的can you could you了,但是我硬要改变要怎么弄呢,于是乎,我学了很多string库封装的函数,翻了好多博客,又敲了两个多小时,没错,string函数太好用了,100多行变成70多行了:
1 #include<iostream> 2 using namespace std; 3 bool isfuhao(char x)//判断是否标点符号 4 { 5 if (x<'0'||x>'9'&& x<'A'|| x>'Z'&& x<'a' || x>'z') 6 return true; 7 return false; 8 } 9 int main() 10 { 11 int n; 12 cin>>n; 13 getchar(); 14 while(n--) 15 { 16 string s; 17 getline(cin,s); 18 cout<<s<<endl; 19 while(s[0]==' ') s.erase(s.begin());//删除最前面的空格 20 while(s[s.length()-1]==' ') s.erase(s.end()-1);//删除最后面的空格 21 for(int i=0;i<s.length();i++) 22 { 23 if(s[i]==' '){ 24 while(s[i+1]==' ') s.erase(s.begin()+i+1);//删掉空格后面多的空格 25 if(isfuhao(s[i+1])){ 26 s.erase(s.begin()+i);//如果后面是标点符号,现在这个空格也删掉 27 } 28 } 29 } 30 for(int i=0;i<s.length();i++) 31 if(isupper(s[i])&&s[i]!='I')//把除i外大写的换成小写 32 s[i]=tolower(s[i]); 33 34 for(int beg=0;;beg++){ 35 beg=s.find("can you",beg);//从beg处开始找can you 找到后将c的下标赋给beg 36 if(beg==-1) break; //没找到,break 37 if( ( beg==0||isfuhao(s[beg-1]) )&& ( beg+7==s.length()||isfuhao(s[beg+7]) ) )//判断一下能不能换 38 s.replace(beg,7,"A can");//在beg处替换七个字符,替换成A can(换成A是因为不和下面的I冲突) 39 } 40 //换could you i me 都是一样的流程 41 for(int beg=0;;beg++){ 42 beg=s.find("could you",beg); 43 if(beg==-1) break; 44 if( ( beg==0||isfuhao(s[beg-1]) )&& ( beg+9==s.length()||isfuhao(s[beg+9]) ) ) 45 s.replace(beg,9,"A could"); 46 } 47 48 for(int beg=0;;beg++){ 49 beg=s.find("I",beg); 50 if(beg==-1) break; 51 if( (beg==0||isfuhao(s[beg-1])) && (beg+1==s.length() || isfuhao(s[beg+1])) ) 52 s.replace(beg,1,"you"); 53 } 54 55 for(int beg=0;;beg++){ 56 beg=s.find("me",beg); 57 if(beg==-1) break; 58 if( (beg==0||isfuhao(s[beg-1])) && (beg+2==s.length() || isfuhao(s[beg+2])) ) 59 s.replace(beg,2,"you"); 60 } 61 62 for(int i=0;i<s.length();i++)//最后把A换回来 63 { 64 if(s[i]=='?') s[i]='!'; 65 if(s[i]=='A') s[i]='I'; 66 } 67 cout << "AI: " << s << endl; 68 } 69 return 0; 70 }
串的匹配
BF算法太简单就不说了,重点是kmp的next数组,next数组的定义很重要,next【j】表示当T[i] != P[j]时,j指针的下一个位置,那么怎么求这个位置呢,这就是kmp的精华,先看看代码:
void getNext(String p) { next[0] = -1; int j = 0; int k = -1; while (j < p.length - 1) { if (k == -1 || p[j] == p[k]) { next[++j] = ++k; } else { k = next[k]; } } }
我们来看while里面的两个分支,第一个是k==-1或p[j] == p[k]就执行,啥意思呢?
先来看看如果j=0时如果不匹配怎么办

所以在代码中才会有next[0] = -1;这个初始化。那当p[j] == p[k]的时候,next[j+1]为什么等于 next[j] + 1呢,因为在P[j]之前已经有P[0 ~ k-1] == p[j-k ~ j-1]。这时候现有P[k] == P[j],就可以得到P[0 ~ k-1] + P[k] == p[j-k ~ j-1] + P[j]。
即next[j+1] == k + 1 == next[j] + 1。
再来看第二个分支,p[j] != p[k]时,k=next【k】;

这样,next数组就弄出来了,其他就没什么难的了。
接下来的目标:把主席树弄懂,把dfs线段树debug,把十字链表敲出来,还有复习深搜和广搜。如果这些都弄完了的话就去debug一开始的1-8吧。

浙公网安备 33010602011771号