KMP算法應用

1、2018 京東校招筆試題 兩個子串

題目描述
給定一個字符串s, 請計算輸出含有連續兩個s作爲子串的最短字符串。 注意兩個s可能有重疊部分。例如,"ababa"含有兩個"aba".

輸入描述:
輸入包括一個字符串s,字符串長度length(1 ≤ length ≤ 50),s中每個字符都是小寫字母.
輸出描述:
輸出一個字符串,即含有連續兩個s作爲子串的最短字符串。
示例1

輸入
abracadabra
輸出
abracadabracadabra

思路如下圖: 

實現代碼:

#include<iostream>
#include<string>
using namespace std;
int* getNextArray(string str2) {
	if (str2.length() == 1) {
		int* next = new int[1];
		next[0] = -1;
		return next;
	}
	int* next = new int[str2.length()];
	next[0] = -1;
	next[1] = 0;
	int i = 2;
	int cn = 0;
	while (i < str2.length()+1) {//多求一位
		if (str2[i - 1] == str2[cn]) {
			next[i++] = ++cn;
		}
		else if (cn > 0) {
			cn = next[cn];
		}
		else {
			next[i++] = 0;
		}
	}
	return next;
}
int main() {
	string s1;
	while (cin >> s1) {
		int* p = getNextArray(s1);
		string res = s1 + s1.substr(p[s1.length()]);
		cout << res;
	}
	return 0;
}

2、判斷二叉樹B是否爲二叉樹A的子樹

思路:序列化二叉樹+KMP算法

即將兩顆二叉樹序列化然後判斷B(tree2)序列化的結果是否爲A(tree1)序列化的子串即可

完整代碼:

#include<iostream>
#include<stack>
#include<string>
using namespace std;
struct TreeNode {
	int val;
	struct TreeNode* left;
	struct TreeNode* right;
	TreeNode(int data):val(data), left(NULL),right(NULL){
	}
};
//先序序列遍歷
void preOrder(TreeNode* root) {
	if (root != NULL) {
		stack<TreeNode*> s;
		s.push(root);
		while (!s.empty()) {
			TreeNode* p = s.top();
			s.pop();
			cout << p->val;
			if (p->right != NULL)
				s.push(p->right);
			if (p->left != NULL)
				s.push(p->left);
		}
		cout << endl;
	}
}
//先序創建二叉樹
TreeNode* preCreate() {
	int data;
	TreeNode *p;
	cin >> data;
	if (data == -1) {
		p = NULL;
	}	
	else {
		p = new TreeNode(data);
		p->left = preCreate();
		p->right = preCreate();
	}
	return p;
}
//先序序列化
string preSerial(TreeNode* root) {
	if (root == NULL) {
		return "#_";
	}
	string res = to_string(root->val) + '_';
	res += preSerial(root->left);
	res += preSerial(root->right);
	return res;
}
//求next數組
int* getNextArray(string str2) {
	if (str2.length() == 1) {
		int* next = new int[1];
		next[0] = -1;
		return next;
	}
	int* next = new int[str2.length()];
	next[0] = -1;
	next[1] = 0;
	int i = 2;
	int cn = 0;
	while (i < str2.length()) {
		if (str2[i - 1] == str2[cn]) {
			next[i++] = ++cn;
		}
		else if (cn > 0) {
			cn = next[cn];
		}
		else {
			next[i++] = 0;
		}
	}
	return next;
}
//KMP算法返回子串在母串出現位置
int getIndexOf(string str1, string str2) {
	if (str1.length() == 0 || str2.length() == 0)
		return -1;
	int i1 = 0;
	int i2 = 0;
	int* next = getNextArray(str2);
	while (i1 < str1.length() && i2 < str2.length()) {
		if (str1[i1] == str2[i2]) {
			i1++;
			i2++;
		}
		else {
			if (next[i2] == -1) {
				i1++;
			}
			else {
				i2 = next[i2];
			}
		}
	}
	return i2 == str2.length() ? i1 - i2 : -1;
}
void display(int res) {
	if (res == -1)
		cout << "Is not subTree" << endl;
	else
		cout << "Is subTree" << endl;
}
int main() {
	TreeNode* tree1 = preCreate();
	cout << "tree1:" << endl;
	preOrder(tree1);
	TreeNode* tree2 = preCreate();
	cout << "tree2:" << endl;
	preOrder(tree2);
	TreeNode* tree3 = preCreate();
	cout << "tree3:" << endl;
	preOrder(tree3);
	TreeNode* tree4 = preCreate();
	cout << "tree4:" << endl;
	preOrder(tree4);
	string s1 = preSerial(tree1);
	string s2 = preSerial(tree2);
	string s3 = preSerial(tree3);
	string s4 = preSerial(tree4);
	cout <<  "s1:" <<s1 << endl;
	cout <<"s2:" << s2 << endl;
	cout << "s3:" << s3 << endl;
	cout << "s4:" << s4 << endl;
	int res1 = getIndexOf(s1, s2);
	int res2 = getIndexOf(s1, s3);
	int res3 = getIndexOf(s1, s4);
	cout << "tree2:";
	display(res1);
	cout << "tree3:";
	display(res2);
	cout << "tree4:";
	display(res3);
	while (1);
	return 0;
}

測試1:

測試結果:

3、判斷一個字符串是否爲一個子串重複得到

比如:ababababab
就可以由ab重複得到,返回Treu
比如abcabcabc
就可以由abc重複得到,返回True
否則返回false

這也是kmp的變形

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章