字符串面试题
一般面試字符串的題目分四種:1, 基本運算(求長度,連接,比較)2. 格式轉換(atoi, itoa) 3.字符串翻轉 4. 模式匹配。
1. 基本運算
a.?賦值操作
函數原型:int StrAssign(const char *s, char *t)
函數說明:將s的內容付給t
函數定義:
int StrAssign(const char *s, char *t){
?char *p = t;
??while(*s !='\0'){
??*p++ = *s++;
?}
?*p = '\0';
?return 0;
}
b.?連接操作
函數原型:int Concat(char *s, const char *t)
函數說明:將串t連接到串s的尾部,形成一個新串
函數定義:
int Concat(char *s, const char *t){
?//首先找到串s的尾部
?char *p = s;
?while(*p != '\0') p++;//循環結束以后的p就是s的尾部
??while(*t !='\0')???*p++ = *t++;?
??*p='\0';//添加尾部字符
??return 0;
}
c.求長度
函數原型:int StrLen(char *s)
函數說明:返回串s的長度
函數定義:
int StrLen(char *s){
?int len = 0;
?while(*s != '\0'){
??len ++;
??s++;
?}
?return len;
}
d.?字符串比較
函數原型:int StrCmp(const char *s, const char *t)
函數說明:比較兩個串的大小,返回值為-1,0,1表示s<t, s=t,s>t。
函數定義:
int StrCmp(const char *s, const char *t){
?while((*s != '\0')&&(*t != '\0')){
???if(*s++ - *t++ > 0) return 1;
??else if( *s++ - *t++ <0) return -1;
??else return 0;
?}
?return 0;
}
//不區分大小寫的字符串比較函數
int stricmp(const char *s, const char *t){?
?while((*s != '\0')&&(*t != '\0')){??
??if(toupper(*s++) - toupper(*t++) > 0) return 1;
??else if(toupper(*s++) - toupper(*t++) <0) return -1;
??else return 0;
?}
?return 0;
}
2.?整數與字符串之間的相互轉換
?
?
a.將字符串轉換成整數
?
?
??????例如有一字符串str[]=“1234”,最直觀的轉換方法就是依次將每一個字符轉換成相應的數字,然后乘10累加,即((1*10+2)*10+3)*10+4。想要得到每一位相應的數字,只需用每個字符減去數字0的ASCII碼,即2= str[1]-'0'。
??????如果字符串首字符標示的是一個負數,即str[0]=='-'。那么此時應該設置一個符號判斷標示位(用來判斷以后得到的整數是否需要乘-1),并把要處理的字符數組下標設置為1。
??????int str_to_int(char str[])
??????{
????????int i=0, isNeg=0,num=0;
????????if(str[0]=='-')
??????????{isNeg=1;
???????????i=1;
??????????}
????????while(str[i])
??????????{num=num*10+(str[i]-'0');
???????????i++;
??????????}
????????if(isNeg)
??????????num*=-1;
????????return num;
??????}
b.將整數轉換為字符串
??????將整數轉換為字符串相對要復雜些。通過取模,并結合商與余數的關系,可以有幾種方法。例如,123除以100,商為1,余數為23,這樣,首先可以把“1”保存到字符串里。然后23除以10,商為2,余數為3。這樣就可以得到字符串“123”了。但是,怎樣來確定整數的位數確實比較麻煩。有一種相對簡單的方法。
??????首先將123除10取模,得到數字3,此時商為12。再將12除10取模,得到數字2,商為1。這樣,我們可以得到字符串“321”,接著進行一次逆序即可得到想要的字符串。
????同樣,如果該整數小于0,我們需要人為地將其變成正數,再進行取模運算!!
???????char int_to_str(int num,char str[])
???????{
????????int i=0,j=0,isneg=0;
????????char temp[10];
????????if(num<0)
??????????{
???????????num*=-1;
???????????isNeg=1;
??????????}
????????do{
???????????temp[i]=(num)+'0';
???????????num/=10;
???????????i++;
????????????}while(num)????//使用do-while結構保證當num為0時也執行循環。
????????if(isNeg)
??????????temp[i++]='-';
????????while(i>0)
??????????str[j++]=temp[--i];
????????str[j]='\0';??????//字符串結束符不能忘掉。
???????}
?
3、字符串翻轉,這里有兩種翻轉,第一種是翻轉整個字符串,第二種是翻轉句子中的單詞。
a. 翻轉整個字符串
函數原型:void Reverse(char *s1)
函數說明:"abcd"=>"dcba"
函數定義:
void Reverse(char *s1){
?char *p = s1;?
?while(*p!='\0'){
??p++;
?}
?char ch_t;
?p--;
?char *p1 = s1;
?while(p1 < p){
??ch_t = *p1;
??*p1 = *p;
??*p = ch_t;?
??p--;
??p1++;??
?}
?return;
}
b. 翻轉句子中的單詞
函數原型:void ReverseWord(char *s1)
函數說明:"today is sunday"=>"sunday is today"
函數定義:
void ReverseWord(char *c){
//先對整個句子進行翻轉
?char *p = c;
?char *p1;
?int count = 0;??
//在對句子的每個單詞進行翻轉
?while(*p!='\0'){
??p++;
??count++;
??if((*p == ' ')||(*p =='\0')){
???//記錄下這個位置
???p1 = p - count;
???if(*p == ' ') p++;
???ReverseChar(p1, 0, count-1);???
???count = 0;
??}
?}
Reverse(c);
}
在ReverseWord函數調用了ReverseChar函數對給出字符串的起始位置做翻轉
void ReverseChar(char *ch,??int start, int end){
?char *p1 = ch;
?char *p = ch;
?char ch_t;
?while(start < end){
??ch_t = *(p1+start);
??*(p1+start) = *(p + end);
??*(p + end) = ch_t;?
??end --;
??start++;??
?}
}
?
4、字符串的模式匹配
給一個串T,和子串P,返回是否子串p是否和串T中有子串匹配,如果有,返回位置;沒有返回0。
假設P為給定的子串,T是待查找的字符串
T:???t0??????t1?????t2??????t3?.... tm-1?... tn-1
P:???p0??????p1?????p2??????p3?.....pm-1??????
用P中的字符依次與T中的字符進行比較,遇到不相等的字符,則可將P右移一個字符,從新進行比較,直到某次匹配成功或者到達P的最右字符移出T為止。
如:?若P="aaaba", T="aaabbaaaba",?則匹配過程如下圖
?T:?????a???a???a???b???b???a???a???a???b??a
?P:?????a???a???a???b???a?????????????????????????????????????????????????????????????????
????????????a???a???a???b???a?????????????????
????????????????????????????????.....
????????????????????????????a???a???a???b??a????????????
上述樸素字符串匹配算法的時間復雜性為0(M*N).
樸素匹配算法函數定義:
int Index(const char *res, const char *str, int position)
{
?int i=0;
?int j=0;
?int lengthRes=strlen(res);
?int lengthStr=strlen(str);
?while(i<=lengthRes && j<=lengthStr)
?{
??if(res[i]==str[j])
??{
???++i;?
???++j;
??}
??else if(j == lengthStr)
???return i-lengthStr;
??else
??{
???//如果不匹配, j從頭開始重新匹配
???i=i-j+1;
???j=0;
??}
?}
?return -1;
}
在樸素的匹配算法中,從頭回溯重新匹配是沒有必要的。
KMP主要解決兩個問題:
a. 當字符串比較出現不等時,確定下一趟比較前應該將P右移多少個字符;?
b. P右移后,應該從哪個字符開始和T中剛才比較時不等的那個字符繼續開始比較.
每當一趟匹配過程中出現字符比較不等時,不需回溯主串S的指針,而是利用已經得到的“部分匹配”結果將模式串向右“滑動”盡可能遠的一段距離后,繼續進行比較。模式串到底向右滑動多少,在KMP算法中是用一個數組來存儲的。針對模式串中的每個索引j,都將有一個對應的值。此值的含義為模式串中位置從0到j-1構成的串中所出現的首尾相同的子串的最大長度加1。
因此,KMP算法計算next數組是關鍵。
void GetNext(char *p, int next[]){
?int i,j, slen;
?slen = strlen(p);
?i = 0;
?next[0] = -1;
?j = -1;
?while(i<slen){
??if((j==-1)||(p[i] == p[j])){
???++i;
???++j;
???next[i] = j;
??}
??else{
???j = next[j];
??}
?}
}
KMP匹配算法函數:
int Index_KMP(char *s, char *p, int pos, int next[]){
?int i,j, slen, plen;
?i = pos -1;
?j =-1;
?slen = strlen(s);
?plen = strlen(p);
?while((i<slen)&&(j<plen)){
??if((j == -1)||(s[i] == p[j])){
???++i;
???++j;
??}
??else{
???j = next[j];
??}
?}
??if(j>=plen) return i - plen;
??else return -1;
?}
總結
- 上一篇: 在继承中派生类成员的访问权限测试
- 下一篇: amazon题代码