1. 程式人生 > >字串面試題C++

字串面試題C++

重要概念

1.迴文
2.子串(連續)
3.子序列(不連續)
4.字首:指除了最後一個字元以外,一個字串的全部頭部組合。
5.字尾:指除了第一個字元以外,一個字串的全部尾部組合。

          • 例:“ABCDAB"的字首為[A, AB, ABC, ABCD, ABCDA],字尾為[BCDAB, CDAB, DAB, AB, B],共有元素為"AB”,長度為2;
            6.字首樹(Trie樹)
            7.字尾樹與字尾樹組
            8.匹配
            字典序

重要操作

與陣列有關的操作:增刪改查
字元的替換
字串的旋轉

題目常見型別

1.規則判斷
判斷字串是否符合整數規則,返回整數
判斷字串是否符合浮點數規則,返回浮點數
判斷字串是否符合迴文規則
2.數字運算
int與long範圍有限,通常用字串拼大整數,與大整數相關的加減乘除操作,需要模擬筆算的過程,
3.與陣列操作有關的型別
陣列有關的調整、排序等操作
快速排序的劃分過程需要掌握與改寫
4.字元計數
雜湊表進行統計
固定長度的陣列代替雜湊表C/C++(ASCII碼範圍0-255,用256長度陣列)
滑動視窗問題,尋找無重複字元子串問題,計算變位詞問題
5.動態規劃問題
最長公共子串問題
最長公共子序列問題
最長迴文子串
最長迴文子序列
6.搜尋型別(如何將string1變換為string2,每一步變換過程)
寬度優先搜尋
深度優先搜尋
7.高階演算法與資料結構解決的問題
Manacher演算法解決最長迴文子串問題
KMP演算法解決字串匹配問題
字首樹結構
字尾樹與字尾樹組

示例一

給定彼此獨立的兩顆樹,判斷t1中是否有與t2拓撲結構完全相同的子樹。
分析:將兩顆樹序列化,然後用KMP演算法進行字串匹配。時間複雜度為 O ( N + M ) O(N+M)

示例二

給定兩個字串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”。判斷兩個字是否互為旋轉詞。
分析:最優解時間複雜度為 O ( N ) O(N)
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]移到左側。要求:時間複雜度為 O ( N ) O(N) ,額外空間複雜度為 O ( 1 ) O(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;
}

示例八

給定一個字串,其中只包含左括號或右括號,判斷是不是整體有效的括號字串。
時間複雜度為 O ( N ) O(N) ,額外空間複雜度為 O ( 1 ) O(1)
分析:使用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;

時間複雜度為 O ( N ) O(N) ,額外空間複雜度為 O ( N ) O(N)

#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;
}