【算法淺析】CCF中常見的關於字符串處理相關問題分析

(一)CCF 201409-3 字符串匹配

  • 題目描述

給出一個字符串和多行文字,在這些文字中找到字符串出現的那些行。你的程序還需支持大小寫敏感選項:當選項打開時,表示同一個字母的大寫和小寫看作不同的字符;當選項關閉時,表示同一個字母的大寫和小寫看作相同的字符。

  • 輸入格式

  輸入的第一行包含一個字符串S,由大小寫英文字母組成。
  第二行包含一個數字,表示大小寫敏感的選項,當數字爲0時表示大小寫不敏感,當數字爲1時表示大小寫敏感。
  第三行包含一個整數n,表示給出的文字的行數。
  接下來n行,每行包含一個字符串,字符串由大小寫英文字母組成,不含空格和其他字符。

  • 輸出格式

輸出多行,每行包含一個字符串,按出現的順序依次給出那些包含了字符串S的行。

  • ** 樣例輸入**

Hello
1
5
HelloWorld
HiHiHelloHiHi
GrepIsAGreatTool
HELLO
HELLOisNOTHello

  • 樣例輸出

HelloWorld
HiHiHelloHiHi
HELLOisNOTHello

  • 樣例說明

在上面的樣例中,第四個字符串雖然也是Hello,但是大小寫不正確。如果將輸入的第二行改爲0,則第四個字符串應該輸出。

  • 評測用例規模與約定

1<=n<=100,每個字符串的長度不超過100。

  • 試題分析
    主要是分敏感和不敏感兩種情況,如果不敏感,則將所有字符串都轉爲小寫,然後使用strstr(s1,s2)進行比較,若敏感,則直接進行比較,需要對常見的字符串處理函數相當熟悉
  • 代碼
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
void mylowers(char *ps){
	while(*ps){
		if('A'<=*ps&&*ps<='Z'){
			*ps+='a'-'A';
		}
		ps++;
	}

}
int main(int argc, char** argv) {
	const int N=100;
	 char key[N+1],s[N+1],lowerkey[N+1],lowers[N+1];
	 int option,n;
	 cin>>key>>option>>n;
	 strcpy(lowerkey,key);
	 mylowers(lowerkey);
	 for(int i=1;i<=n;i++){
	 	cin>>s;
	 	if(option==0){
	 		//大小寫無關
			strcpy(lowers,s);
			mylowers(lowers);
			//strstr(s1,s2)用於判斷 s2是否爲s1的字串 
			if(strstr(lowers,lowerkey)){
				cout<<s<<endl;
			}
		 }else if(option==1){
		 	//大小寫相關
			 if(strstr(s,key)) {
			 	cout<<s<<endl;
			 }
		 }
	 }
	return 0;

(二)CCF 201604-3 路徑解析

  • 問題描述

   在操作系統中,數據通常以文件的形式存儲在文件系統中。文件系統一般採用層次化的組織形式,由目錄(或者文件夾)和文件構成,形成一棵樹的形狀。文件有內容,用於存儲數據。目錄是容器,可包含文件或其他目錄。同一個目錄下的所有文件和目錄的名字各不相同,不同目錄下可以有名字相同的文件或目錄。
  爲了指定文件系統中的某個文件,需要用路徑來定位。在類 Unix 系統(Linux、Max OS X、FreeBSD等)中,路徑由若干部分構成,每個部分是一個目錄或者文件的名字,相鄰兩個部分之間用 / 符號分隔。
  有一個特殊的目錄被稱爲根目錄,是整個文件系統形成的這棵樹的根節點,用一個單獨的 / 符號表示。在操作系統中,有當前目錄的概念,表示用戶目前正在工作的目錄。根據出發點可以把路徑分爲兩類:
  絕對路徑:以 / 符號開頭,表示從根目錄開始構建的路徑。
  相對路徑:不以 / 符號開頭,表示從當前目錄開始構建的路徑。
  例如,有一個文件系統的結構如下圖所示。在這個文件系統中,有根目錄 / 和其他普通目錄 d1、d2、d3、d4,以及文件 f1、f2、f3、f1、f4。其中,兩個 f1 是同名文件,但在不同的目錄下。
在這裏插入圖片描述
  對於 d4 目錄下的 f1 文件,可以用絕對路徑 /d2/d4/f1 來指定。如果當前目錄是 /d2/d3,這個文件也可以用相對路徑 …/d4/f1 來指定,這裏 … 表示上一級目錄(注意,根目錄的上一級目錄是它本身)。還有 . 表示本目錄,例如 /d1/./f1 指定的就是 /d1/f1。注意,如果有多個連續的 / 出現,其效果等同於一個 /,例如 /d1///f1 指定的也是 /d1/f1。
  本題會給出一些路徑,要求對於每個路徑,給出正規化以後的形式。一個路徑經過正規化操作後,其指定的文件不變,但是會變成一個不包含 . 和 … 的絕對路徑,且不包含連續多個 / 符號。如果一個路徑以 / 結尾,那麼它代表的一定是一個目錄,正規化操作要去掉結尾的 /。若這個路徑代表根目錄,則正規化操作的結果是 /。若路徑爲空字符串,則正規化操作的結果是當前目錄。

  • 輸入格式

  第一行包含一個整數 P,表示需要進行正規化操作的路徑個數。
  第二行包含一個字符串,表示當前目錄。
  以下 P 行,每行包含一個字符串,表示需要進行正規化操作的路徑。

  • 輸出格式

共 P 行,每行一個字符串,表示經過正規化操作後的路徑,順序與輸入對應。

  • 樣例輸入

7
/d2/d3
/d2/d4/f1
…/d4/f1
/d1/./f1
/d1///f1
/d1/
///
/d1/…/…/d2

  • 樣例輸出

/d2/d4/f1
/d2/d4/f1
/d1/f1
/d1/f1
/d1
/
/d2

  • 評測用例規模與約定

  1 ≤ P ≤ 10。
  文件和目錄的名字只包含大小寫字母、數字和小數點 .、減號 - 以及下劃線 _。
  不會有文件或目錄的名字是 . 或 … ,它們具有題目描述中給出的特殊含義。
  輸入的所有路徑每個長度不超過 1000 個字符。
  輸入的當前目錄保證是一個經過正規化操作後的路徑。
  對於前 30% 的測試用例,需要正規化的路徑的組成部分不包含 . 和 … 。
  對於前 60% 的測試用例,需要正規化的路徑都是絕對路徑。

  • 試題分析
    先獲取一行,使用字符串處理函數進行處理’
  • 代碼
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
void mygetline(char *pc){
	char c;
	//獲取一行 
	while((c=getchar())!='\n'&&c!=EOF){
		*pc++=c;
	}
	*pc='\0';
}
int main(){
	const int N=100;
	char s[N+1];
	int p;
	int pos;
	string cp,line;
	//輸入數據
	cin>>p>>cp;
	getchar();
	for(int i=1;i<=p;i++){
		mygetline(s);
		line=s;
		//非根路徑處理,輸入空串的時候 
		if(line[0]!='/') {
			line=cp+'/'+line+'/';
		}
		//去除多個'/'
		//str.find(str2),當str2是str的子串時,返回其在str中第一次出現的位置
		//如果str2不是str的字串,那麼返回string::npos即-1 
		while((pos=line.find("//"))!=-1){
			int count=2;
			while(line[pos+count]=='/'){
				count++;
			}
			//erase()1.str.erase(it)刪除單個元素,it爲需要刪除的元素迭代器
			 
			line.erase(pos,count-1);
		}
		//去除"./"
		while((pos=line.find("/./"))!=-1){
			// str.length(pos,length)其中pos爲需要開始
			//刪除的起始位置,length爲刪除的字符個數 
			line.erase(pos+1,2);
		}
		//去除最後的'/'
		if(line.size()>1&&line[line.size()-1]=='/') {
			line.erase(line.size()-1);
		}
		//去除"../"
		while((pos=line.find("/../"))!=-1){
			if(pos==0){
				line.erase(pos,3);
			}else{
				int spos;
				//int rfind(char c, int pos = npos) const;//從pos開始從後向前查找字符c在當前串中的位置
				//rfind的查找截止值並不是pos,而是pos+strlen(c)-1
				spos=line.rfind("/",pos-1);
				//刪除區間爲左封閉右開 
				line.erase(spos,pos-spos+3);
			}
			if(line.size()==0){
				line="/";
			}
		}
		cout<<line<<endl; 
	} 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章