今天是字符串的入门题,字符串的题学习建议使用cpp的stl中的string,虽然STL又名sometime time limit,但是自己使用char数组写轮子很容易产生越界导致的RTE或者SE。
同时希望大家能够记住string.h和string的函数,至少看名字要知道他是什么意思,这样才能极大的提高做串类型的题的速度。
废话不多说,直接进入正题。
题目0:自动修正
简单的大小写替换题。代码给两种
//python
//print(input().upper())
//cpp头文件啥的省略嗷
for(int i =0;i<len;i++){
if(s[i]>='a'&&s[i]<='z') printf("%c",s[i]-'a'+'A');
else printf("%c",s[i]);
}
题目1:小书童——密码
简单的对每一个字母+n即可,但是注意整个要对26取模保证始终是字母。
for(int i = 0; s[i]<len ; i++)
printf("%c",(s[i]-'a'+n)%26+'a')
题目2:笨小猴
实不相瞒,这道题我坐着我觉得我也蛮笨的(bushi),坑点在于:
- 你的min如果不对book数组中的0进行特别判定的话,那么你会WA;
- 一般素数是不会判断0的(没错,我一开始的接口没有判断0),所以我在0卡了好一会儿。
代码如下#include<stdio.h> #include<string.h> #include<math.h> char memo[105]; int book[26]; int max(int a, int b) { return a > b ? a : b; } int min(int a, int b) { return a < b ? a : b; } bool Is_Prime(int num) { if (num == 0) return false; if (num == 1) return false; if (num == 2) return true; int bound = sqrt(num); for (int i = 2; i <= bound + 1; i++) { if (num % i == 0) return false; } return true; } int main() { int mmax = -1, mmin = 999; scanf("%s", memo); int len = strlen(memo); for (int i = 0; i < len; i++) book[memo[i] - 'a']++; for (int i = 0; i < 26; i++) { mmax = max(mmax, book[i]); if (book[i] == 0) continue; else mmin = min(mmin, book[i]); } if (Is_Prime(mmax - mmin)) return 0 * printf("Lucky Word\n%d\n", mmax - mmin); else return 0 * printf("No Answer\n0\n"); }
题目3:口算计算题
根据题目进行模拟即可,但是这里有个重点是如何区分三个还是两个的情况(所以这题的难度真的是普及-吗?)。
具体实现方式见代码和注释。#include<string> #include<iostream> #include<stdio.h> using namespace std; int Num_lenth(int num){ int len = 0; if (num < 0 || num == 0) len++; while (num) len++, num /= 10; return len; } int To_num(string s){ int ans = 0, len = s.size(); for (int i = 0; i < len; i++) ans = ans * 10 + s[i] - '0'; return ans; } int main(){ string sa, sb; int a, b, n; char ch, copy; cin >> n; for (int i = 1; i <= n; i++){ cin >> ch >> sa >> sb; if (ch >= '0' && ch <= '9') sa = ch + sa, ch = copy;//因为第一个不是字母,所以我们把copy赋予ch方便后续判断 //string类加法就是拼接字符串,copy是上一轮的字符。 a = To_num(sa), b = To_num(sb); //本来打算用atoi但是因为是string就得手造轮子 int a_len = Num_lenth(a), b_len = Num_lenth(b); if (ch == 'a') printf("%d+%d=%d\n%d", a, b, a + b, a_len + b_len + 2 + Num_lenth(a + b)), copy = ch; else if (ch == 'b') printf("%d-%d=%d\n%d", a, b, a - b, a_len + b_len + 2 + Num_lenth(a - b)), copy = ch; else if (ch == 'c') printf("%d*%d=%d\n%d", a, b, a * b, a_len + b_len + 2 + Num_lenth(a * b)), copy = ch; if (i < n) cout << endl; //这里注意,多输出换行爆0 } return 0; }
题目4:标题统计
假如你是顺序做题的话,经历了上面的题的洗礼,这道题简直就是送分题,但是,这里科普一下:gets函数请勿在比赛的时候使用(C11以上已经不允许使用了)。#include<stdio.h> #include<string.h> int main(){ char s[10]; int ans = 0, len; fgets(s, 10, stdin); len = strlen(s); for (int i = 0; i < len; i++) { if (s[i] >= 'A' && s[i] <= 'Z') ans++; if (s[i] >= 'a' && s[i] <= 'z') ans++; if (s[i] >= '0' && s[i] <= '9') ans++; } return 0 * printf("%d\n", ans); }
题目5:文字处理软件
按照题目使用库函数即可(自己写费时费力)#include<cstdio> #include<cstring> const int MAXN = 105; char text[MAXN], temp[MAXN]; int main(){ int n, op, a, b; scanf("%d\n%s", &n, text); for (int i = 1; i <= n; i++) { scanf("%d", &op); if (op == 1) { scanf("%s", temp); strcat(text, temp); printf("%s\n", text); } else if (op == 2) { scanf("%d %d", &a, &b); text[a + b] = '\0'; strcpy(temp, text + a); strcpy(text, temp); printf("%s\n", text); } else if (op == 3) { scanf("%d %s", &a, temp); strcat(temp, text + a); text[a] = '\0'; strcat(text, temp); printf("%s\n", text); } else { scanf("%s", temp); char* ans = strstr(text, temp); if (ans != NULL) printf("%d\n", int(ans - text)); else printf("-1\n"); } } return 0; }
题目6:统计单词数
按照题目要求,请勿使用cin因为cin无法读入空格,这里提供另外一个思路,循环到文件结尾,将文章的每个单词读入string中,然后处理都为大写或者小写,直接strcmp每个string(这里就不写咯)。#include<iostream> #include<cstring> #include<string> using namespace std; int main(){ string article, word; int pass_len, word_len, t = 0, pos = 0, j; getline(cin, word), getline(cin, article); word_len = word.size(), pass_len = article.size(); for (int i = 0; i < word_len; i++) word[i] = toupper(word[i]); //不采用-'a'+'A'的方式主要是需要多写一个判断其是不是属于'a'到'z'之间 for (int i = 0; i < pass_len; i++) article[i] = toupper(article[i]); for (int i = 0; i <= pass_len - word_len; i++){ for (j = 0; j < word_len; ++j){ if (article[j + i] != word[j]) break; if (i > 0 && article[i - 1] != ' ') break; } if (j == word_len && (article[j + i] == ' ' || j + i == pass_len)) if (++t == 1) pos = i; } if (t == 0) cout << -1; else cout << t << " " << pos; return 0; }
题目7:手机
由于每个字母需要按的次数是固定的,所以我们打表即可。#include<iostream> #include<cstdio> #include<string> using namespace std; int cnt[26] = { 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4 }; int main(){ string s; getline(cin, s); int ans = 0, len = s.length(); for (int i = 0; i < s.length(); i++){ if (s[i] >= 'a' && s[i] <= 'z') ans += cnt[s[i] - 'a']; if (s[i] == ' ') ans++; } return 0* printf("%d", ans); }
题目8:honoka的键盘
遍历两次,同时使用book数组来保证’VK’没有被使用,且由于只能变换一次保证最多的VK,因此答案必然是VK的数目或者VK+1。#include<cstdio> using namespace std; int n, ans, flag, book[105]; char s[105]; int main(){ scanf("%d%s", &n, s); for (int i = 1; i < n; i++) if (s[i - 1] == 'V' && s[i] == 'K') ans++, book[i - 1] = book[i] = 1; for (int i = 1; i < n; i++) if (!flag && !book[i - 1] && !book[i] && s[i - 1] == s[i]) flag = 1, ans++; return 0 * printf("%d\n", ans); }
题目9:单词覆盖还原
题目含义就是,只要b开头,第二个是o或第三个是y或第二三是oy,那么就算一个boy;girl同理#include<iostream> #include<string> using namespace std; int main() { int bcnt = 0, gcnt = 0; string s; cin >> s; for (int i = 0; i <= s.length(); i++) { if (s[i] == 'b' || s[i + 1] == 'o' || s[i + 2] == 'y')bcnt++; if (s[i] == 'g' || s[i + 1] == 'i' || s[i + 2] == 'r' || s[i + 3] == 'l') gcnt++; } cout << bcnt << endl << gcnt << endl; return 0; }
题目10:数字反转(升级版)
前面有一个简易版本的数字反转,这个要难一点,但是依旧只要按照题目所说就可以正确做出来(就是细节特别多),这里使用的是栈。
没错,细节多到炸,我以为按照题意不会出现1.00100这种数字,结果在这个点疯狂WA,而且还有很多奇形怪状的坑点,调BUG调了40min。#include<stdio.h> #include<iostream> #include<string.h> #include<stack> using namespace std; char memo[30]; int main() { stack<char> s; scanf("%s", memo); int len = strlen(memo); int signal_pos = len, zero_flag = 1; for (int i = 0; i < len; i++) if (memo[i] < '0' || memo[i]>'9') signal_pos = i;//非整数 for (int i = 0; i < signal_pos; i++) s.push(memo[i]);//符号前进栈 while (s.size() != 0) {//输出 char temp = s.top(); if (temp != '0') zero_flag = 0; if (zero_flag == 1); else cout << temp; s.pop(); } if (zero_flag == 1) cout << 0;//说明符号前整个都是0,只有一个0 cout << memo[signal_pos];//输出符号或整数的最后一位 zero_flag = 1; for (int i = signal_pos + 1; i < len; i++) { if (zero_flag == 0) s.push(memo[i]); else { if (memo[i] == '0') continue;//原来数据的前导0我们不要 else { zero_flag = 0;//不是前导0了 s.push(memo[i]); } } } if (s.size() == 0 && signal_pos != len && signal_pos != len - 1) cout << 0; //第一个说明小/分数后面是0,第二个说明是整数,第三个说明是百分数 zero_flag = 1; while (s.size() != 0) {//输出 char temp = s.top(); if (temp != '0') zero_flag = 0; if (zero_flag == 1); else cout << temp; s.pop(); } return 0; }
题目11:斯诺登的密码
这题首先,你得打表,不然你就得写很多很多ifelseif;其次,然后对于平方后取模,建议也直接打表,不然前导0去除很恶心。//先挖个坑,由于环境不一样,所以你直接copy会CE #pragma warning(disable:4996) #include<stdio.h> #include<algorithm> using namespace std; char dic[30][10] = { "zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty","a","both","another","first","second","third" }; int ind[30] = { 0,1,4,9,16,25,36,49,64,81,00,21,44,69,96,25,56,89,24,61,0,1,4,1,1,4,9 },ans[10]; char s[100]; int main(){ int pos = 0, flag = 0; for (int i = 0; i < 6; i++){ scanf("%s", s); for (int j = 0; j < 26; j++){ if (!strcmp(s, dic[j])){ ans[pos++] = ind[j]; break; } } } sort(ans, ans + pos); for (int i = 0; i < pos; i++){ if (flag) printf("%.2d", ans[i]); else{ if (ans[i]){ printf("%d", ans[i]); flag = 1; } } } if (!flag) printf("0"); return 0; }
题目12:你的飞碟在这里
按照题目来,此题没有坑点(早期做的题目,代码懒得重写)。#include<stdio.h> #include<string.h> char st[7],gr[7]; int main(){ long long int star,group; int stl,gro; scanf("%s%s",st,gr); star=1,group=1,stl=strlen(st),gro=strlen(gr); for(int i=0;i<stl;i++) star*=(st[i]-'A'+1); star=star%47; for(int i=0;i<gro;i++) group*=(gr[i]-'A'+1); group=group%47; if(star==group) printf("GO"); else printf("STAY"); return 0; }
题目13:语句解析
scanf属于格式输入,使用scanf可以定向输入想要位置的值,然后按照题目要求就可以做了。#include<stdio.h> int main(){ int a[3] = { 0,0,0 }; char s1, s2; while (scanf("%c:=%c;", &s1, &s2) == 2) if (s2 >= '0' && s2 <= '9') a[s1 - 'a'] = s2 - '0'; else a[s1 - 'a'] = a[s2 - 'a']; return 0 * printf("%d %d %d", a[0], a[1], a[2]); }
题目14:垂直柱状图
K&R C书籍上的原题,属于比较繁琐的字符串模拟,重点是你要先找到最大的数来决定你要输出的最大范围#include<cstdio> #include<string> #include<iostream> using namespace std; int book[26]; int max(int x, int y) { return x > y ? x : y ;} int main(){ int n, maxn = -1;; string a; for (int i = 0; i < 4; i++){ getline(cin,a); n = a.length(); for (int j = 0; j < n; j++) if (a[j] >= 'A' && a[j] <= 'Z') book[a[j] - 'A']++; } for (int i = 0; i < 26; i++) maxn = max(maxn, book[i]); for (int i = maxn; i > 0; i--) { for (int j = 0; j < 26; j++) { if (book[j] >= i)printf("* "); else printf(" "); } printf("\n"); } for (int i = 0; i < 26; i++) printf("%c ", i + 'A'); return 0; }
今天的字符串入门就是这些啦,内容虽然不难,但题都或多或少的繁琐(考虑多种边界条件),会了基本之后才能为后面更难的字符串题目(字符串的难题基本都得构造出状态机,因此需要很好的基础),一天杀一单子题还是有点刺激。