算法基礎——字符串相關(二)
目錄:
- 應用實例
- 替換空格【劍指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;