今天讲的字符串:
不多说,直接看题
一.表达式求值
题目大意:
输入一行一个表达式,计算其答案 表达式包含非负整数、加减乘除、括号
两种做法
·栈
·表达式树
这里更推荐表达式树,因为栈是先压进去,逆序操作。在进行逆序操作时即从右往左计算,实际应该是从左往右计算,所以会出现计算不符合顺序的问题。从而出现错误。
而表达式树则又称为“表达式目录树”,以数据形式表示语言级代码,它是一种抽象语法树或者说是一种数据结构。——摘自百度百科
可见,每个父节点都是一种运算符,子节点为数字。运算时从底层向上层依次按父节点符号操作子节点即可。
先贴栈的代码:
1 /* 2 1+(2+3)*4 3 21 4 */ 5 6 #include <iostream> 7 #include <stack> 8 using namespace std; 9 10 const int MAXN = 10000 + 10; 11 char str[MAXN]; 12 stack<int> nums; 13 stack<char> symbol; 14 15 void pop() 16 { 17 int a = nums.top();nums.pop(); 18 int b = nums.top();nums.pop(); 19 char s = symbol.top();symbol.pop(); 20 int ans; 21 switch(s) 22 { 23 case '+':ans=a+b;break; 24 case '-':ans=b-a;break; 25 case '*':ans=a*b;break; 26 case '/':ans=b/a;break; 27 } 28 nums.push(ans); 29 } 30 int main() 31 { 32 cin >> (str+1); 33 for(int i=1;str[i]!=0;i++) 34 { 35 char c=str[i]; 36 if('0'<=c&&c<='9') 37 { 38 nums.push(c-'0'); 39 } else { 40 if(c==')') 41 { 42 while(symbol.top() != '(') pop(); 43 symbol.pop(); 44 } else if (c=='+' || c=='-') 45 { 46 while(!symbol.empty() 47 &&symbol.top()!='+' 48 &&symbol.top()!='-' 49 &&symbol.top()!='(') pop(); 50 symbol.push(c); 51 } else symbol.push(c); 52 } 53 } 54 while(!symbol.empty())pop(); 55 cout<<nums.top()<<endl; 56 57 return 0; 58 }
在计算上面图中的例子时,栈会出错。
下面给出表达式树的代码:
1 /* 2 10+(2+3)*4 3 30 4 */ 5 6 #include <iostream> 7 #include <stack> 8 #include <cstring> 9 using namespace std; 10 11 const int MAXN = 10000 + 10; 12 char str[MAXN]; 13 14 int solve(int l, int r) 15 { 16 17 int pos=-1; 18 int flag=0; 19 int level=2; // 0:+- 1:*/ 20 for(int i=l;i<=r;i++) 21 { 22 if(str[i]=='(')flag++; 23 if(str[i]==')')flag--; 24 if(flag == 0 && (str[i]<'0'||str[i]>'9'||str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/')&&str[i]!=')') 25 { 26 int l=-1; 27 switch(str[i]) 28 { 29 case '+':case '-':l=0;break; 30 case '*':case '/':l=1;break; 31 } 32 if(level >= l) 33 { 34 level=l; 35 pos=i; 36 } 37 } 38 } 39 if(pos==-1) 40 { 41 if(str[l]=='('&&str[r]==')') return solve(l+1,r-1); 42 int x=0; 43 for(int i=l;i<=r;i++) 44 x=x*10+str[i]-'0'; 45 return x; 46 } 47 int a = solve(l, pos-1); 48 int b = solve(pos+1, r); 49 int ans; 50 switch(str[pos]) 51 { 52 case '+':ans=a+b;break; 53 case '-':ans=a-b;break; 54 case '*':ans=a*b;break; 55 case '/':ans=a/b;break; // 3*2/3 56 } 57 return ans; 58 } 59 int main() 60 { 61 cin >> (str+1); 62 cout << solve(1, strlen(str+1)) << endl; 63 64 return 0; 65 }
二.字符串统计
题目大意:给定N个字符串,判断不同的字符串有多少个。
做法:hash
所谓hash就是把每个字符串设成一个值,每个字符串的值要不同,所以操作的时候只要弄的奇奇怪怪就好啦(个人理解,不喜勿喷)
这样比较字符串就成了比较数值的问题。
哈希碰撞:所谓哈希碰撞是指在哈希时难免会遇到有重复的数值,解决方案可以为双哈希。
例如:在哈希时会模一个很大的质数,假设这个质数为mod,当遇到某个数m时(m<mod)m % mod = m
但是当遇到另一个数n时,n恰巧为 m + mod 那么 n % mod = m 两串字符对应值都为m,产生了碰撞。
在洛谷有道模板题,链接:https://www.luogu.org/problemnew/show/P3370
hash代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 long n; 7 char s[10001]; 8 long long ms[10101]={0}; 9 long long ans=1; 10 11 int main() 12 { 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) 15 { 16 cin>>s; 17 18 int len=strlen(s); 19 for(int j=0;j<len;j++) 20 ms[i]=(ms[i]*131+(long long)s[j])%233333333333+233317; 21 22 } 23 sort(ms+1,ms+n+1); 24 for(int i=1;i<n;i++) 25 { 26 if(ms[i]!=ms[i+1]) 27 ans++; 28 } 29 printf("%d",ans); 30 31 32 }