字符串面試題的特點
廣泛性
1.字符串可以看做字符類型的數組,與數組排序、查找、調整有關
2.很多其它類型面試題可看作自字符串類型的面試題。
需掌握的概念
1.迴文
題目(1)
判斷一個字符串是否爲迴文
解法:遞歸
遞歸思路:一個迴文字符串其中內部也是迴文。所以,我們只需要以去掉兩端的字符的形式一層層檢查,每一次的檢查都去掉了兩個字符,這樣就達到了縮少問題規模的目的。新問題與原問題有着相同的形式當去掉兩端字符後的字符串,其產生的新問題同樣是檢查這個字符串是否迴文。
遞歸的結束需要簡單情景
①. 字符串長度可能會奇數或偶數:
如果字符串長度是奇數,字符串會剩下最中間那位字符,但其不影響迴文。當檢查到長度爲1的時候即代表此字符串是迴文
如果字符串長度是偶數,當兩端的字符串兩兩比較檢查後不會剩下字符。即檢查到長度爲0的時候即代表此字符串是迴文
②. 如果檢查到兩端兩個字符不相同。則說明此字符串不是迴文,直接返回0,不需要繼續檢查
#include<iostream>
#include<string>
using namespace std;
int huiwen(int low,int high,char str[],int length){
if(length==0||length==1){
return 1;
}
if(str[low]!=str[high]){
return 0;
}
huiwen(low+1,high-1,str,length-2);
}
int main(){
char str[20];
cin>>str;
int length=strlen(str);
int a=huiwen(0,length-1,str,length);
if(a==1){
cout<<"迴文!";
}
else
cout<<"不迴文!";
}
題目(2)
要求你,給你一個字符串,可在任意位置添加字符,最少再添加幾個字符,可以使這個字符串成爲迴文字符串。
輸入
第一行給出整數N(0
#include<iostream>
#include<string>
using namespace std;
int huiwen(int low,int high,char str[],int length){
if(length!=0&&length!=1){
if(str[low]==str[high]){
return huiwen(low+1,high-1,str,length-2);
}
else
return min(huiwen(low+1,high,str,length-1),huiwen(low,high-1,str,length-1))+1;
}
return 0;
}
int main(){
char str[20];
cin>>str;
int res=0;
int length=strlen(str);
int a=huiwen(0,length-1,str,length);
cout<<a;
}
第二種思路:(在我看來,該代碼用到了動態規劃,我還不太懂)
其實就是最長公共子序列的變種,將原序列str倒置後得到tmp。求出最長公共子序列的長度,則這些就是迴文字串,剩下的就是沒有匹配的字符的個數。用總長度減去最長公共子序列的長度,就得到需要添加的字符數量。
代碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define MAX 1010
int res[MAX][MAX];
int main()
{
int ncase, i, j;
scanf("%d", &ncase);
while(ncase--)
{
string str, tmp;
cin>>str;
tmp = str;
reverse(tmp.begin(), tmp.end()); //倒置
for(i = 0; i < str.size(); ++i)
{
for(j = 0; j < tmp.size(); ++j) //res[i][j]爲最長公共子序列的長度
{
if(str[i] != tmp[j])
res[i + 1][j + 1] = max(res[i + 1][j], res[i][j + 1]);
else
res[i + 1][j + 1] = res[i][j] + 1;
}
}
printf("%d\n", str.size() - res[i][j]); //總長度減去res[i][j]就是不匹配字符個數
}
}
2.子串(連續)
3.子序列(不連續)
4.前綴樹(Trie樹)
參考了博客trie樹(前綴樹)
#include<iostream>
#include<string>
using namespace std;
#define MAX 26 //字符集大小
struct TrieNode{
bool isStr; //標識是否是一個完整的字符串
struct TrieNode *next[MAX];
};
/*插入*/
void Insert(TrieNode *root , char *word)
{
TrieNode *location=root;
while(*word){
if(location->next[*word-'a']==NULL){
TrieNode *newNode=new TrieNode();
newNode->isStr=false;
memset(newNode->next,NULL,sizeof(newNode->next));//初始化
location->next[*word-'a']=newNode;
}
location=location->next[*word-'a'];//location指向字符串在前綴樹中下一個位置
word++; //當前字符在字符串中位置
}
//字符串已經全部添加到前綴樹
//標識前綴樹到該節點位置爲完整字符串
location->isStr=true;
}
//查找
bool Search(TrieNode *root , char *word)
{
TrieNode *location=root;
while(*word&&location!=NULL){
location=location->next[*word-'a'];
word++;
}
return(location!=NULL&&location->isStr );
}
void Delete(TrieNode *location){
for(int i=0;i<MAX;i++){
if(location->next[i]!=NULL){
Delete(location->next[i]);
}
}
delete location;
}
int main(){
//初始化前綴樹的根節點,注意這裏結構體指針的初始化
TrieNode *root=new TrieNode();
root->isStr =false;
//前綴樹中每一個節點的下一個節點,分配空間,注意memset的使用
memset(root->next,NULL,sizeof(root->next));
Insert(root,"a");
Insert(root,"bcd");
Insert(root,"xyz");
Insert(root,"abcdef");
if(Search(root,"bcd"))
cout<<"exist"<<endl;
else
cout<<"no exist"<<endl;
Delete(root);
}
5.後綴樹和後綴數組
6.匹配
7.字典序
需掌握的操作
1.與數組有關的操作:增刪改查
2.字符的替換
3.字符串的旋轉
字符串題目常見類型
規則判斷
1.判斷字符串是否符合整數規則
2.判斷字符串是否符合浮點數規則
3.判斷字符串是否符合迴文字符串規則
等等
數字運算
用字符串實現大整數
與大整數相關的加減乘除操作,需要模擬筆算的過程。
與數組操作有關的類型(重點)
1.數組有關的調整、排序等操作需要掌握
2.快速排序的劃分過程,需要掌握和改寫。
字符計數
1.哈希表
2.固定長度的數組(代替哈希表)
3.常見問題:滑動窗口問題,尋找無重複字符子串問題,計算變位詞等問題。
動態規劃問題
1.最長公共子串
2.最長公共子序列
3.最長迴文子串
4.最長迴文子序列
等
搜索類型
1.寬度優先搜索
2.深度優先搜索
高級算法與數據結構解決的問題
1.Manacher算法解決最長迴文子串問題(馬拉車算法)
2.KMP算法解決字符串匹配問題
3.前綴樹結構
4.後綴樹與後綴數組
5.通常面試很少出現。