字串面試題C++
重要概念
1.迴文
2.子串(連續)
3.子序列(不連續)
4.字首:指除了最後一個字元以外,一個字串的全部頭部組合。
5.字尾:指除了第一個字元以外,一個字串的全部尾部組合。
-
-
-
-
- 例:“ABCDAB"的字首為[A, AB, ABC, ABCD, ABCDA],字尾為[BCDAB, CDAB, DAB, AB, B],共有元素為"AB”,長度為2;
6.字首樹(Trie樹)
7.字尾樹與字尾樹組
8.匹配
字典序
- 例:“ABCDAB"的字首為[A, AB, ABC, ABCD, ABCDA],字尾為[BCDAB, CDAB, DAB, AB, B],共有元素為"AB”,長度為2;
-
-
-
重要操作
與陣列有關的操作:增刪改查
字元的替換
字串的旋轉
題目常見型別
1.規則判斷
判斷字串是否符合整數規則,返回整數
判斷字串是否符合浮點數規則,返回浮點數
判斷字串是否符合迴文規則
2.數字運算
int與long範圍有限,通常用字串拼大整數,與大整數相關的加減乘除操作,需要模擬筆算的過程,
3.與陣列操作有關的型別
陣列有關的調整、排序等操作
快速排序的劃分過程需要掌握與改寫
4.字元計數
雜湊表進行統計
固定長度的陣列代替雜湊表C/C++(ASCII碼範圍0-255,用256長度陣列)
滑動視窗問題,尋找無重複字元子串問題,計算變位詞問題
5.動態規劃問題
最長公共子串問題
最長公共子序列問題
最長迴文子串
最長迴文子序列
6.搜尋型別(如何將string1變換為string2,每一步變換過程)
寬度優先搜尋
深度優先搜尋
7.高階演算法與資料結構解決的問題
Manacher演算法解決最長迴文子串問題
KMP演算法解決字串匹配問題
字首樹結構
字尾樹與字尾樹組
示例一
給定彼此獨立的兩顆樹,判斷t1中是否有與t2拓撲結構完全相同的子樹。
分析:將兩顆樹序列化,然後用KMP演算法進行字串匹配。時間複雜度為
。
示例二
給定兩個字串str1與str2,如果兩個字串中出現的字元種類一樣且每種字元出現的次數也一樣,那麼str1與str2互為變形詞,請判斷兩個字元是否互為變形詞。
分析:使用雜湊表分別記錄每個字元出現的次數。也可以建立一個256的陣列,代替雜湊表。
bool simpleWord(char *str1, char *str2, const int &length) {
int num1[256] = { 0 };
int num2[256] = { 0 };
for (int i = 0; i < length; ++i) {
++num1[str1[i]];
}
for (int i = 0; i < length; ++i) {
++num2[str2[i]];
}
bool flag = true;
for (int i = 0; i < length; ++i) {
if (num1[i] != num2[i]) {
flag = false;
break;
}
}
return flag;
}
示例三
如果一個字串str,把字串str前面任意的部分挪到後面去形成的字串叫做str的旋轉詞。比如str=“1234”,則旋轉詞有“1234”,“2341”,“3412”,“4123”。判斷兩個字是否互為旋轉詞。
分析:最優解時間複雜度為
。
1.判斷str1與str2是否長度相等
2.如果長度相等,生成str1+str1的大字串
3.用KMP演算法判斷大字串中是否含有str2
#include<iostream>
#include<thread>
#include<string>
#include<vector>
using std::cout;
using std::endl;
void getNext(int *next,const std::string &str) {
int i = 0;
next[0] = -1;
int k = -1;
while (i < (str.length() )) {
if (k == -1 || str[i] == str[k]) {
++i;
++k;
next[i] = k;
}
else {
k = next[k];
}
}
}
bool subString(const std::string &str1, const std::string &str2, std::vector<int> &position) { //查詢str2是否在str1中,並將位置儲存在position中,可重複可重疊出現
int *next = new int[str2.length()+1];
getNext(next, str2);
int i = 0; // str1
int j = 0;// str2
while (i<str1.length()){
if (j == -1 || str1[i] == str2[j]) {
++i;
++j;
if (j >= str2.length()) {
position.push_back(i - str2.length());
j = next[j];
}
}
else{
j = next[j];
}
}
delete[] next;
if (position.empty()) {
return false;
}
else{
return true;
}
}
bool rotateWord(const std::string str1, const std::string str2) { //判斷str2是否為str1的旋轉詞
std::string doublestr1 = str1 + str1;
std::vector<int> positon;
return subString(doublestr1, str2, positon);
}
int main() {
std::string str1 = "1234";
std::string str2 = "2341";
std::vector<int> position;
cout << rotateWord(str1, str2) << endl;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例四
給定一個字串str,請在單詞間做逆序調整。
舉例:
“pig loves dog”逆序成“dog loves pig”
分析:
1.實現將字串區域性所有字元逆序的函式f
2.利用f將字串所有字元逆序
“god sevol gip”
3.找到逆序後的字串中每一個單詞的區域利用f將每一個單詞的區域逆序
#include<iostream>
#include<thread>
#include<string>
#include<vector>
using std::cout;
using std::endl;
void reverseWord(std::string &str) { //字串反向
for (int i = 0; i < str.length() / 2; ++i) {
auto temp = str[i];
str[i] = str[str.length() - i - 1];
str[str.length() - i - 1] = temp;
}
}
void reverseWord(std::string &str, const int &start,const int &end) { //字串從start到end 反轉
for (int i = 0; i < (end - start + 1) / 2; ++i) {
char temp = str[start + i];
str[start + i] = str[end - i];
str[end - i] = temp;
}
}
void reverseSentence(std::string &str) {
reverseWord(str);
int start = 0;
int end = -2;
for (int i = 0; i < str.length(); ++i) {
if (str[i] == ' ') {
start = end + 2;
end = i - 1;
reverseWord(str, start, end);
}
if (i == (str.length() - 1)) {
start = end + 2;
end = str.length() - 1;
reverseWord(str, start, end);
}
}
}
int main() {
std::string str1 = "dog loves pig.";
std::string str2 = "0123456789";
std::vector<int> position;
reverseSentence(str1);
for (auto i : str1) {
cout << i << endl;
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例五
給定一個字串str,和一個整數i。i代表str中的位置,將str[0…i]移到右側,str[i+1…N-1]移到左側。要求:時間複雜度為
,額外空間複雜度為
。
舉例:str=“ABCDE”,i=2,將str調整為“CDEAB”
分析:
1.首先將0-i逆序
2.將i+1-N-1逆序
3.將str整體逆序
#include<iostream>
#include<thread>
#include<string>
#include<vector>
using std::cout;
using std::endl;
void reverseWord(std::string &str) { //字串反向
for (int i = 0; i < str.length() / 2; ++i) {
auto temp = str[i];
str[i] = str[str.length() - i - 1];
str[str.length() - i - 1] = temp;
}
}
void reverseWord(std::string &str, const int &start,const int &end) { //字串從start到end 反轉
for (int i = 0; i < (end - start + 1) / 2; ++i) {
char temp = str[start + i];
str[start + i] = str[end - i];
str[end - i] = temp;
}
}
void translationWord(std::string &str, const int &position) { // 將字串0~position移到最右側
reverseWord(str, 0, position);
reverseWord(str, position + 1, str.length() - 1);
reverseWord(str);
}
int main() {
std::string str1 = "dog loves pig.";
std::string str2 = "0123456789";
std::vector<int> position;
translationWord(str2, 5);
for (auto i : str2) {
cout << i << endl;
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例六
給定一個字串型別的陣列strs,請找到一種拼接順序,使得將所有字串拼接起來的大字串是所有可能性中字典順序最小的,並返回這個大字串。
舉例:str=[“abc”,“de”]。可以拼接成“abcde”“deabc”,選擇字典順序小的“abcde”。
分析:直接對字串排序會出現問題,例如[“b”,“ba”]會拼接成“bba”,但是“bab”是最小。應當比較str1+str2與str2+str1的大小。
#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<algorithm>
using std::cout;
using std::endl;
bool cmp(std::string str1, std::string str2) {
return str1 + str2 < str2 + str1 ? true : false;
}
std::string minJoint(std::vector<std::string> strs) {
sort(strs.begin(), strs.end(),cmp);
std::string str = "";
for (auto i : strs) {
str += i;
}
return str;
}
int main() {
std::string str1 = "dog loves pig.";
std::string str2 = "0123456789";
std::string strs[2] = { "b","a" };
std::vector<std::string> position = {"b","ba"};
str1 = minJoint(position);
for (auto i : str1) {
cout << i << endl;
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例七
給定一個字串str,將其中所有空格字元替換成“%20”,假設str後面有足夠的空間。
分析:
1.計算出空格數量,得到最終字元的長度。
2.從後往前寫入字元。
#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<algorithm>
using std::cout;
using std::endl;
void replaceSpace(std::string &str) {//將空格替換為“%20”
int spaceNum = 0;
int lenOld = str.length() - 1;
for (auto i : str) {
if (i == ' ') {
++spaceNum;
}
}
std::string addition(spaceNum * 2, ' ');
str = str + addition;
int lenNew = lenOld + 2 * spaceNum;
for (int i = lenOld; i >= 0; --i) {
if (str[i] != ' ') {
str[lenNew--] = str[i];
}
else if (str[i] == ' ') {
str[lenNew--] = '0';
str[lenNew--] = '2';
str[lenNew--] = '%';
}
}
}
int main() {
std::string str1 = "dog loves pig";
std::string str2 = "0123456789";
std::string strs[2] = { "b","a" };
std::vector<std::string> position = {"b","ba"};
int n = 10;
std::string str(n,'c');
replaceSpace(str1);
for (auto i : str1) {
cout << i << endl;
}
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}
示例八
給定一個字串,其中只包含左括號或右括號,判斷是不是整體有效的括號字串。
時間複雜度為
,額外空間複雜度為
。
分析:使用num計算左右括號數,如果是左括號num++,如果是右括號num–,遍歷的過程中如果出現num<0,則直接返回false,最終如果num==0,則返回true,否則為false。
例項九
給定一個字串str,返回str的最長無重複字元子串的長度。
分析:求出以str中每個字元結尾的情況下,最長無重複字元子串的長度,並在其中找出最大值返回。
1.使用雜湊表map記錄每一種字元之前出現的位置。
2.整型變數pre,代表上一個字元結尾情況下,最長無重複子串的長度。
3.每次比較第i個字元上次出現的位置與第i-1個字元無重複子串的頭的位置,若第i個字元上次出現的位置在第i-1個字元無重複子串的頭的左側,則len[i] = pre+1;若在右側len[i] =i- map[i]+1;
時間複雜度為 ,額外空間複雜度為 。
#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<algorithm>
using std::cout;
using std::endl;
int maxNoRepeatLength(const std::string &str) {
int hash[256] = { -1 };
int preLength = 1;
memset(hash, -1, 256 * sizeof(int));
hash[str[0]] = 0;
int maxLen = 0;
for (int i = 1; i < str.length(); ++i){
if (hash[str[i]] == -1) {
int len = preLength + 1;
preLength = len;
maxLen = (len > maxLen ? len : maxLen);
hash[str[i]] = i;
}
else
{
if ((i - hash[str[i]]) > preLength) {
int len = preLength + 1;
preLength = len;
maxLen = (len > maxLen ? len : maxLen);
hash[str[i]] = i;
}
else
{
int len = i - hash[str[i]] + 1;
preLength = len;
maxLen = (len > maxLen ? len : maxLen);
hash[str[i]] = i;
}
}
}
return maxLen;
}
int main() {
std::string str1 = "abcdecc";
std::string str2 = "0123456789";
std::string strs[2] = { "b","a" };
std::vector<std::string> position = {"b","ba"};
int n = 10;
std::string str(n,'c');
int i = maxNoRepeatLength(str1);
cout << i << endl;
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
return 0;
}