算法基础——字符串相关(二)
目录:
- 应用实例
- 替换空格【剑指Offer_编程题】
- 第一个只出现一次的字符位置【剑指Offer_编程题】
- 左旋转字符串【剑指Offer_编程题】
- 实现字通配符*【shopee】
- 回文数索引【寒武纪】
- 时间转换【寒武纪】
- 最长区间【京东】
- 寻找子串【京东】
- 迷路的牛牛【网易】
- 安置路灯【网易】
- 万万没想到之聪明的编辑【字节跳动】
- 删除公共字符【好未来】
- 倒置字符串【好未来】
- 名字的漂亮度【华为机试】
- 字符串中找出连续最长的数字串【好未来】
一、应用实例:
1、题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
void replaceSpace(char *str,int length) {
//write code here
}【剑指Offer_编程题】
- 输入格式:一个字符串
- 输出格式:替换空格后的字符串
- 样例输入:
- We Are Happy
- 样例输出:
- We%20Are%20Happy
示例代码:
#include <iostream>
#include <cstring>
using namespace std;
void replaceSpace(char *str,int length) {
int count = 0;
for(int i = 0; i < length; i++){
if(str[i] == ' '){
count++;
}
}
int index;
for(int i = length; i >= 0; i--){
if(count == 0){
break;
}
index = count * 2 + i;
if(str[i] != ' '){
str[index] = str[i];
}else{
str[index - 2] = '%';
str[index - 1] = '2';
str[index] = '0';
count--;
}
}
}
int main(){
char str[1000];
while(gets(str)){
replaceSpace(str, strlen(str));
for(int i = 0; i < strlen(str); i++){
cout << str[i];
}
cout << endl;
}
return 0;
}
2、题目描述:在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
int FirstNotRepeatingChar(string str) {
//write code here
}【剑指Offer_编程题】
- 输入格式:一个字符串
- 输出格式:返回第一个只出现一次的字符的位置,如果没有则返回-1
- 样例输入:
- 样例输出:
示例代码:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int MAX_N = 128;
int loc[MAX_N];
int FirstNotRepeatingChar(string str) {
memset(loc, 0, sizeof(loc));
for(int i = 0; i < str.size(); i++){
loc[str[i]]++;
}
for(int i = 0; i < str.size(); i++){
if(loc[str[i]] == 1){
return i;
}
}
return -1;
}
int main(){
string s;
while(getline(cin, s)){
cout << FirstNotRepeatingChar(s) << endl;
}
return 0;
}
3、题目描述:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
string LeftRotateString(string str, int n) {
//write code here
}【剑指Offer_编程题】
- 输入格式:一个字符串
- 输出格式:循环左移n位后的字符串
- 样例输入:
- abcXYZdef
- 样例输出:
- XYZdefabc
示例代码:
string LeftRotateString(string str, int n) {
if(str.size() == 0){
return str;
}
return str.substr(n % str.size()) + str.substr(0, n % str.size());
}
4、题目描述:在Linux Shell命令下通配符'*'表示0个或多个字符, 现编写一段代码实现通配符'*'的功能,注意只需要实现'*', 不用实现其他通配符。【shopee】
- 输入格式:第一行输入通配字符串,第二行输入要匹配查找的字符串
- 输出格式:输出所有匹配的字串起始位置和长度,每行一个匹配输出。如果不匹配,则输出 -1 0。如果有多个按照起始位置和长度的正序输出。
- 样例输入:
- shopee*.com
- shopeemobile.com
- *.com
- shopeemobile.com
- 样例输出:
- 0 16
- 0 16
- 1 15
- 2 14
- 3 13
- 4 12
- 5 11
- 6 10
- 7 9
- 8 8
- 9 7
- 10 6
- 11 5
- 12 4
- 备注:0 起始位置,16长度
示例代码:
#include <iostream>
#include <string>
#include <set>
using namespace std;
set<int> result;//从第x个字符结尾的串
string s1, s2;
void DFS(int i, int j){
if(j == s1.size()){ //当匹配到了正则式的末尾
result.insert(i);
}else if(i < s2.size()){
if(s1[j] == s2[i]){
DFS(i + 1, j + 1);
}else if(s1[j] == '*'){
DFS(i, j + 1); //*没匹配到
DFS(i + 1, j); //*匹配到了
}
}else if(i == s2.size() && s1[j] == '*' && j == s1.size() - 1){
result.insert(i);
}
}
int main(){
while(cin >> s1 >> s2){
bool flag = false;
int len;
for(int i = 0; i < s2.size(); i++){
if(s1[0] == '*' || s2[i] == s1[0]){
result.clear();
DFS(i, 0);
if(result.size() > 0){
flag = true;
}
for(set<int>::iterator iter = result.begin(); iter != result.end(); iter++){
len = (*iter) - i;
if(len > 0){
cout << i << " " << len << endl;
}
}
}
}
if(!flag){
cout << "-1 0" << endl;
}
}
return 0;
}
5、题目描述:给定一个仅由小写字母组成的字符串。现在请找出一个位置,删掉那个字母之后,字符串变成回文。请放心总会有一个合法的解。如果给定的字符串已经是一个回文串,那么输出-1。【寒武纪】
- 输入格式:第一行包含T,测试数据的组数。后面跟有T行,每行包含一个字符串。
- 输出格式:如果可以删去一个字母使它变成回文串,则输出任意一个满足条件的删去字母的位置(下标从0开始)。例如:bcc,我们可以删掉位置0的b字符。
- 样例输入:
- 3
- aaab
- baa
- aaa
- 样例输出:
- 3
- 0
- -1
示例代码:
#include <iostream>
#include <string>
using namespace std;
bool JudgeStr(string s){
for(int j = 0; j <= s.size() / 2; j++){
if(s[j] != s[s.size() - 1 - j]){
return false;
}
}
return true;
}
int GetLoc(string s){
if(JudgeStr(s)){
return -1;
}
for(int i = 0; i < s.size(); i++){
if(JudgeStr(s.substr(0, i) + s.substr(i + 1))){
return i;
}
}
return -1;
}
int main(){
string s;
int n;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> s;
cout << GetLoc(s) << endl;
}
}
return 0;
}
6、题目描述:给定一个12小时制的时间,请将其转换成24小时制的时间。说明:12小时制的午夜12:00:00AM,对应的24小时制时间为00:00:00。12小时制的中午12:00:00PM,对应的24小时制时间为12:00:00。【寒武纪】
- 输入格式:一个描述12小时制时间的字符串。所有的输入都是合理的,不用考虑输入不合理的情况。
- 输出格式:一个描述24小时制时间的字符串。
- 样例输入:
- 08:03:45PM
- 样例输出:
- 20:03:45
示例代码:
#include <iostream>
#include <string>
using namespace std;
void print(int index, string s){
for(int i = index; i < s.size() - 2; i++){
cout << s[i];
}
cout << endl;
}
int main(){
string s;
while(cin >> s){
if(s[8] == 'P'){
if(s[0] == '1' && s[1] == '2'){
cout << "12";
}else{
cout << (s[0] - '0') * 10 + s[1] - '0' + 12;
}
print(2, s);
}else {
if(s[0] == '1' && s[1] == '2'){
cout << "00";
print(2, s);
}else{
print(0, s);
}
}
}
return 0;
}
7、拉齐有一个01序列,他可以对这个序列进行任意多次变换,每次变换都是把序列的最后若干个元素放到最前面,例如:010011,将最后3个元素011放到最前面,序列变为011010。所有变换结束后,拉齐需要挑出一个全为1的连续区间,要求最大化区间长度。【京东】
- 输入格式:共一行,一个01串,仅包含0或1。序列长度不超过50000。
- 输出格式:一个整数,表示最长区间的长度。
- 样例输入:
- 11011
- 样例输出:
- 4
示例代码1:
#include <string>
#include <iostream>
using namespace std;
int GetMaxSequence(string s){
int result = 0, tmp = 0;
int index = 0;
while(index < s.size()){
while(index < s.size() && s[index] == '1'){
tmp++;
index++;
}
result = max(result, tmp);
tmp = 0;
index++;
}
return result;
}
int main(){
string s;
while(cin >> s){
int result = 0;
if(s[0] != '1' || s[s.size() - 1] != '1'){
cout << GetMaxSequence(s) << endl;
}else{
int count = 0, index = 0;
while(index < s.size() && s[index] == '1'){
count++;
index++;
}
if(index < s.size() - 1){
index = s.size() - 1;
while(index >= 0 && s[index] == '1'){
index--;
count++;
}
}
count = max(count, GetMaxSequence(s));
cout << count << endl;
}
}
return 0;
}
示例代码2:
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
while(cin >> s){
s = s + s;
int result = 0, index = 0, tmpCount;
while(index < s.size()){
tmpCount = 0;
while(index < s.size() && s[index] == '1'){
tmpCount++;
index++;
}
result = max(tmpCount, result);
index++;
}
if(result == s.size()){
cout << result / 2 << endl;
}else{
cout << result << endl;
}
}
return 0;
}
8、题目描述:给出m个字符串S1,S2,...,Sm和一个单独的字符串T。请在T中选出尽可能多的子串同时满足: 1)这些子串在T中互不相交。 2)这些子串都是S1,S2,...,Sm中的某个串。问最多能选出多少个子串。【京东】
- 输入格式:第一行一个数m(1≤m≤10),接下来m行,每行一个串。最后一行输入一个串T。输入中所有单个串的长度不超过100000,串中只会出现小写字母。
- 输出格式:输出一个数,最多能选出多少串。
- 样例输入:
- 3
- aa
- b
- ac
- bbaac
- 样例输出:
- 3
示例代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int MAX_N = 100001;
int nextTable[MAX_N];
struct Node{
int from;
int to;
Node(int f, int t):from(f), to(t){};
};
vector<string> strList;
vector<Node> nodeList;
bool compareAsc(const Node &n1, const Node &n2){
return n1.to < n2.to;
}
void GetNext(string pattern){
int j = 0;
nextTable[j] = -1;
int i = nextTable[j];
while(j < pattern.size()){
if(i == -1 || pattern[j] == pattern[i]){
i++;
j++;
nextTable[j] = i;
}else{
i = nextTable[i];
}
}
}
void GetNode(string s){
for(int m = 0; m < strList.size(); m++){
GetNext(strList[m]);
int i = 0, j = 0;
while(i < s.size()){
if(j == -1 || s[i] == strList[m][j]){
i++;
j++;
}else{
j = nextTable[j];
}
if(j == strList[m].size()){
nodeList.push_back(Node(i - strList[m].size() + 1, i));
j = nextTable[j];
}
}
}
}
int main(){
string s;
int n;
while(cin >> n){
strList.clear();
nodeList.clear();
for(int i = 0; i < n; i++){
cin >> s;
strList.push_back(s);
}
cin >> s;
GetNode(s);
sort(nodeList.begin(), nodeList.end(), compareAsc);
int result = 0, start = 0;
for(int i = 0; i < nodeList.size(); i++){
if(nodeList[i].from >= start){
result++;
start = nodeList[i].to + 1;
}
}
cout << result << endl;
}
return 0;
}
9、题目描述:牛牛去犇犇老师家补课,出门的时候面向北方,但是现在他迷路了。虽然他手里有一张地图,但是他需要知道自己面向哪个方向,请你帮帮他。【网易】
- 输入格式:每个输入包含一个测试用例。每个测试用例的第一行包含一个正整数,表示转方向的次数N(N<=1000)。接下来的一行包含一个长度为N的字符串,由L和R组成,L表示向左转,R表示向右转。
- 输出格式:输出牛牛最后面向的方向,N表示北,S表示南,E表示东,W表示西。
- 样例输入:
- 3
- LRR
- 样例输出:
- E
示例代码:
#include <iostream>
#include <string>
using namespace std;
const int DIRECTION = 4;
void PrintDirec(int i){
switch(i){
case 0:
cout << "N" << endl;
break;
case 1:
cout << "E" << endl;
break;
case 2:
cout << "S" << endl;
break;
case 3:
cout << "W" << endl;
break;
}
}
int main(){
string s;
int n;
while(cin >> n){
cin >> s;
int origin = 0;
for(int i = 0; i < s.size(); i++){
if(s[i] == 'L'){
origin = (origin - 1 + 4) % 4;
}else{
origin = (origin + 1) % 4;
}
}
PrintDirec(origin);
}
return 0;
}
10、题目描述:小Q正在给一条长度为n的道路设计路灯安置方案。为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用'.'表示, 不需要照亮的障碍物格子用'X'表示。小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。小Q希望能安置尽量少的路灯照亮所有'.'区域, 希望你能帮他计算一下最少需要多少盏路灯。【网易】
- 输入格式:输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数接下来每两行一个测试数据, 第一行一个正整数n(1 <= n <= 1000),表示道路的长度。第二行一个字符串s表示道路的构造,只包含'.'和'X'。
- 输出格式:对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。
- 样例输入:
- 2
- 3
- .X.
- 11
- ...XX....XX
- 样例输出:
- 1
- 3
示例代码:
#include <iostream>
#include <string>
using namespace std;
int main(){
int n, strLen;
string s;
cin >> n;
for(int m = 0; m < n; m++){
cin >> strLen >> s;
int result = 0;
for(int i = 0; i < strLen; ){
if(s[i] == '.'){
result++;
i += 3;
}else{
i++;
}
}
cout << result << endl;
}
}
11、题目描述:我叫王大锤,是一家出版社的编辑。我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误。但是,优秀的人总能在平凡的工作中发现真理。我发现一个发现拼写错误的捷径:
1. 三个同样的字母连在一起,一定是拼写错误,去掉一个的就好啦:比如 helllo -> hello
2. 两对一样的字母(AABB型)连在一起,一定是拼写错误,去掉第二对的一个字母就好啦:比如 helloo -> hello
3. 上面的规则优先“从左到右”匹配,即如果是AABBCC,虽然AABB和BBCC都是错误拼写,应该优先考虑修复AABB,结果为AABCC
我特喵是个天才!我在蓝翔学过挖掘机和程序设计,按照这个原理写了一个自动校对器,工作效率从此起飞。用不了多久,我就会出任CEO,当上董事长,迎娶白富美,走上人生巅峰,想想都有点小激动呢!
……
万万没想到,我被开除了,临走时老板对我说: “做人做事要兢兢业业、勤勤恳恳、本本分分,人要是行,干一行行一行。一行行行行行;要是不行,干一行不行一行,一行不行行行不行。” 我现在整个人红红火火恍恍惚惚的……
请听题:请实现大锤的自动校对程序【字节跳动】
- 输入格式:第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。后面跟随N行,每行为一个待校验的字符串。
- 输出格式:N行,每行包括一个被修复后的字符串。
- 样例输入:
- 2
- helloo
- wooooooow
- 样例输出:
- hello
- woow
示例代码:
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
int n;
while(cin >> n){
for(int i = 0; i < n; i++){
cin >> s;
int index = 0;
while(index <= s.size()){
if((index <= s.size() - 3
&& s[index] == s[index + 1]
&& s[index + 2] == s[index + 1])
|| (index <= s.size() - 4
&& s[index] == s[index + 1]
&& s[index + 2] == s[index + 3])){
s = s.substr(0, index + 2) + s.substr(index + 3);
}else{
index++;
}
}
cout << s << endl;
}
}
return 0;
}
12、题目描述:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入They are students.和aeiou,则删除之后的第一个字符串变成“Thy r stdnts.”【好未来】
- 输入格式:每个测试输入包含2个字符串
- 输出格式:输出删除后的字符串
- 样例输入:
- They are students.
- aeiou
- 样例输出:
- Thy r stdnts.
示例代码:
#include <iostream>
#include <string>
using namespace std;
int main(){
string s1, s2;
while(getline(cin, s1)){
getline(cin, s2);
string result = "";
for(int i = 0; i < s1.size(); i++){
if(s2.find(s1[i]) == s2.npos){
result += s1[i];
}
}
cout << result;
}
return 0;
}
13、题目描述:将一句话的单词进行倒置,标点不倒置。比如 I like beijing. 经过函数后变为:beijing. like I【好未来】
- 输入格式:每个测试输入包含1个测试用例: I like beijing. 输入用例长度不超过100
- 输出格式:依次输出倒置之后的字符串,以空格分割
- 样例输入:
- I like beijing.
- 样例输出:
- beijing. like I
示例代码:
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
const int MAX_N = 101;
stack<char * > myStack;
char s[MAX_N];
int main(){
while(gets(s)){
char *token = strtok(s, " ");
while(token != NULL){
myStack.push(token);
token = strtok(NULL, " ");
}
bool flag = false;
while(!myStack.empty()){
if(flag){
cout << " ";
}
cout << myStack.top();
myStack.pop();
flag = true;
}
cout << endl;
}
return 0;
}
14、题目描述:给出一个名字,该名字有26个字符串组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个字母拥有相同的“漂亮度”。字母忽略大小写。给出多个名字,计算每个名字最大可能的“漂亮度”。【华为机试】
- 输入格式:整数N,后续N个名字
- 输出格式:每个名称可能的最大漂亮程度
- 样例输入:
- 2
- zhangsan
- lisi
- 样例输出:
- 192
- 101
示例代码:
#include <iostream>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 26;
int a[MAX_N];
int main(){
string s;
int n;
while(cin >> n){
for(int m = 0; m < n; m++){
memset(a, 0, sizeof(a));
cin >> s;
for(int i = 0; i < s.size(); i++){
int loc = tolower(s[i]) - 'a';
a[loc]++;
}
sort(a, a + MAX_N);
int sum = 0;
int factor = MAX_N;
for(int i = MAX_N - 1; i >= 0 && a[i] != 0; i--){
sum += a[i] * factor;
factor--;
}
cout << sum << endl;
}
}
return 0;
}
15、题目描述:读入一个字符串str,输出字符串str中的连续最长的数字串【好未来】
- 输入格式:测试输入包含1个测试用例,一个字符串str,长度不超过255。
- 输出格式:在一行内输出str中里连续最长的数字串。
- 样例输入:
- abcd12345ed125ss123456789
- 样例输出:
- 123456789
示例代码:
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int main(){
string s;
while(getline(cin, s)){
int index = 0;
string tmp, result = "";
int maxLen = 0;
while(index != s.size()){
if(isdigit(s[index])){
tmp = "";
while(index != s.size() && isdigit(s[index])){
tmp += s[index];
index++;
}
if(tmp.size() > maxLen){
maxLen = tmp.size();
result = tmp;
}
}else{
index++;
}
}
cout << result << endl;
}
return 0;
}
参考文献:
[1]杨泽邦、赵霖. 计算机考研——机试指南(第2版). [M]北京:电子工业出版社,2019.11;