洛谷题单-字符串题解

目前只使用字符数组
P1914 小书童——密码 思路: 1.利用字符串结尾为'\0'停止循环 2.循环相对位置(位置成环?)利用取模运算 for(int i = 0;s[i];i++)putchar((s[i]-'a'+n)%26 + 'a');
P5733 【深基6.例1】自动修正
思路:
1.利用[停止读取时返回EOF]不断读取
while((s=getchar()) != EOF) ...
P1125 笨小猴
思路:
1.统计各字母
    I:先放进数组后统计
    cin >> s;
    for(int i = 0;s[i];i++) a[s[i]-'a']++;
    II:边读边放
    while((s = getchar()) != EOF) ...
2.遍历找最大最小
3.质数判定
    I:注意特判2,0,1
P1957 口算练习题(不使用字符串)
难点?:
1.每次需判定第一个数据是否为运算符且后续处理麻烦
2.无法(会很麻烦)拼接计算长度(使用字符数组)
思路:
1.使用fgets读取一整行后逐步处理
2.判定是否为运算符
3.若为运算符则修改中间变量,否则直接读取
    I.读取:利用sscanf..不读取空格的特性直接读取数字
5.既然无法拼接那么就新建一个然后将整个运算结果放入计算长度即可
    I.储存:利用sprintf储存至新的字符数组后计算长度即可

分割线————————————————————————————————————————————————————————————————————

启用字符串(STL) 

P5015 标题统计
思路:
1.挨个统计并计算(效率低)
2.利用cin不读取空格(getline都读取),使用字符串直接计算长度(虽然说字符数组也可以)
P5734 【深基6.例6】文字处理软件
String常用操作
1.拼接:直接+/x.appen(str)
2.比大小:比较的时候,从字符串左边开始,一次比较每个字符,直接出现差异、或者其中一个串结束为止。
比如ABC与ACDE比较,第一个字符相同,继续比较第二个字符,由于第二个字符是后面一个串大,所以不再继续比较,结果就是后面个串大。
再如ABC与ABC123比较,比较三个字符后第一个串结束,所以就是后面一个串大。
所以,长度不能直接决定大小,字符串的大小是由左边开始最前面的字符决定的。(来源baidu)
3.返回长度:s.size()/s.length();
4.切割:s.substr(p,len)从第p个位置截取len个字符并返回 (个人感觉不常用)
5.插入:s.insert(p,str)在第p个位置之前插入str
6.查找(很常用):s.find(str,[p])从第p个位置开始查找且可以省略(默认从0开始查找)
    I:找不到返回string::nops需强转int才能返回-1;
综上所述,直接调用相关指令即可。
P1308 统计单词数(find具体应用)
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
	int ans = 0,first = 0,next = 0;
	string s, word;
	//string型读取一整行
	getline(cin, word);
	getline(cin, s);
	//转小写,可能会浪费常量时间?
	for (int i = 0; word[i]; i++)if (word[i] >= 'A' && word[i] <= 'Z') word[i] += 'a' - 'A';
	for (int i = 0; s[i]; i++)if (s[i] >= 'A' && s[i] <= 'Z') s[i] += 'a' - 'A';
	
	//判定是否为首进行处理?
	//再进行空格判断会很麻烦,不如直接增加空格

	//特征查找:单词的前后都为空格,但首位则不一样
	word = ' ' + word + ' ';
	s = ' ' + s + ' '; //结尾也要加,否则为‘\0’
	if ((int)s.find(word) == -1) {
		 cout << -1 << endl;
		 return 0;
	}
	else {
		first = s.find(word);
		next = first;
		//利用substr截断后处理剩余字符串?
		//没必要,直接+1往后判断直到为-1

		//解决字符串计数问题
		while (next != -1) {
			ans++;
			next = s.find(word, next + 1);
		}
		cout << ans << ' ' << first << endl;
	}
}
思路:
1.string读取一行采用getline(cin,str)
2.string可以当作字符数组使用逐个遍历调用tolower()转小写
3.根据特征判断:单词前后都有空格而首尾没有,而句子尾部也没有标点所以直接修改源字符串和待查找数据(使得前后都有空格便于查找)
4.遍历查找:while(n != -1){
        ans++; //统计
        n = s.find(str,n+1);

 字符串映射

P1603 斯诺登的密码(字符串映射)
思路:
1.数字与字符串存在某种对应关系,采用map映射,如果符合条件则进行储存
  I:因为0一定比其他正整数小所以如果有的话一定会在首,而前导零要去掉,所以不做记录
  II:最终只需“打印”出结果,并不需要进一步操作,所以只需要根据数据特征选择性打印0即可
2.从小到大排列sort快排
3.输出:如果首部的数字小于10则利用c的特性printf("0%d",x);即可解决
  I:判断是否为首部(循环if判断/直接打印首部(数组各元素默认为0)根据条件进行循环)
P1765 手机(字符串映射)
思路:
1.利用映射关系直接打印计算
2.利用字符串查找(因为各字母唯一,可以直接判断,如果情况更复杂(比如出现重复的情况)则参考第一项)

分割线————————————————————————————————————————————————————————————————————

P3741 honoka的键盘
思路:
1.如果对可以操作的字符串“XX”进行修改的话最多增加一个
2.所以遍历VK并进行覆盖,遍历能修改的如果能就+1,输出结果即可
P1321 单词覆盖还原(残缺字符串判断)
思路:
1.判定子集
2.根据特征如果某个字符串为“abc”,则符合条件的那一位一定为a || b || c

以上只适用于不出现重复字符
P1553 数字反转(升级版)
思路:
1.使用STL,分别进行擦除,提取字串,字串(特征)查找
代码:
#include <string>
#include <iostream>
#include <algorithm>
std::string reverse(std::string s) {
    int zeroCount = 0;
    std::reverse(s.begin(), s.end());
    for (auto i : s) {
        if (i == '0')
        {
            zeroCount++;
        }
        else {
            break;
        }
    }
    s.erase(s.begin(), s.begin() + zeroCount);
    return (s == "" ? "0" : s);
}
std::string deleteTail(std::string s) {
    int zeroCount = 0,len = s.length();
    for (int i = len - 1; i >= 0 ; i--)
    {
        if (s[i] == '0') //疏忽+偷懒
        {
            zeroCount++;
        }
        else {
            break;
        }
    }
    s.erase(s.end()-zeroCount, s.end()); //zeroCount如果为0,不清除末尾的数字吗?(x.end()返回的是哪个元素的指针?'\0'?)
    return (s == "" ? "0" : s);
}

int main() {
    std::string s, left, right;
    std::cin >> s;
    for (auto i : s) {
        if (i == '/') {
            left = s.substr(0, s.find('/'));
            right = s.substr(s.find('/')+1);//find返回下标
            std::cout << reverse(left) << '/' <<deleteTail(reverse(right));
            return 0;
        }
        if (i == '.') {
            left = s.substr(0, s.find('.'));
            right = s.substr(s.find('.')+1);//?
            std::cout << reverse(left) << '.' << deleteTail(reverse(right)) << std::endl;
            return 0;
        }
    }
    if (s[s.length()-1] == '%') { //?
        std::cout << reverse(s.substr(0, s.length() - 1)) << '%'; //左闭右开
    }
    else {
        std::cout << reverse(s);
    }
    return 0;
}

 字符读取

对于某一类需要单个字符进行操作且后续不需要进行二次处理的时候,一般采用边读边处理的方法,更简洁

P1200 [USACO1.1]你的飞碟在这儿Your Ride Is Here
思路:
1.逐个读入字符并计算
2.判断输出
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
    int n1 = 1,n2 = 1;
    char s;
    while((s = getchar()) != '\n') {
        n1 *= s - 'A' + 1;
    }
    while((s = getchar()) != '\n') {
        n2 *= s - 'A' + 1;
    }
    if((n1%47) == (n2%47)) cout << "GO" <<endl;
    else cout << "STAY" << endl;
}
P1598 垂直柱状图
思路:
1.不断读取字符并累计储存至对应数组
2.根据条件进行输出
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
    #ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
    freopen("output.out","w",stdout);
    #endif
    char s;
    int a[26] = {},max = -1;
    while(cin >> s) if(s >= 'A' && s<= 'Z') a[s-'A']++;
    for(int i = 0;i <26;i++) if(a[i] > max) max = a[i];
    //从上到下打印
    for(int i = max;i >0;i--){
        for(int j = 0;j <26;j++){
            if(a[j] >= i) printf("* ");
            else printf("  ");
        }
        printf("\n");
    }
    cout << "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" << endl;
    return 0;
}

 //未完待续

posted @ 2020-07-16 20:29  WooPooW  阅读(517)  评论(0)    收藏  举报