1. 拓撲結構相同的子樹
對於兩棵彼此獨立的二叉樹A和B,請編寫一個高效算法,檢查A中是否存在一棵子樹與B樹的拓撲結構完全相同,節點取值也要相同。
給定兩棵二叉樹的頭結點A和B,請返回一個bool值,代表A中是否存在一棵同構於B的子樹。
思路1:遍歷樹A,若遍歷到的節點C取值與B的根節點取值一樣,則判斷以B為根和以C為根的樹結構是否相同。時間復雜度:O(N*M)。 N:A的節點數,M:B的節點數。
思路2:將樹A和樹B序列化為字符串,然后用KMP算法在字符串A中尋找子串B。時間復雜度:O(N+M)
知識點:樹的遍歷;樹結構匹配;樹的序列化;KMP算法

1 // 思路1 2 /* 3 struct TreeNode { 4 int val; 5 struct TreeNode *left; 6 struct TreeNode *right; 7 TreeNode(int x) : 8 val(x), left(NULL), right(NULL) { 9 } 10 };*/ 11 12 class IdenticalTree { 13 public: 14 bool chkIdentical(TreeNode* A, TreeNode* B) { 15 if (B==NULL) return true; 16 return pre_order(A, B); 17 } 18 bool pre_order(TreeNode* A, TreeNode* B){ 19 if(A==NULL) return false; 20 bool flag=false; 21 if(A->val == B->val) 22 flag = judge(A, B); 23 if(flag) 24 return true; 25 else 26 return pre_order(A->left, B) || pre_order(A->right, B); 27 } 28 29 bool judge(TreeNode* root1, TreeNode* root2){ 30 if(root1 == NULL && root2 == NULL) return true; 31 if(root1 == NULL && root2 != NULL) return false; 32 if(root1 != NULL && root2 == NULL) return false; 33 if(root1->val != root2->val) return false; 34 return judge(root1->left, root2->left) && judge(root1->right, root2->right); 35 } 36 };

1 // 思路2 2 /* 3 struct TreeNode { 4 int val; 5 struct TreeNode *left; 6 struct TreeNode *right; 7 TreeNode(int x) : 8 val(x), left(NULL), right(NULL) { 9 } 10 };*/ 11 12 class IdenticalTree { 13 public: 14 bool chkIdentical(TreeNode* A, TreeNode* B) { 15 string strA = pre_serial(A); 16 string strB = pre_serial(B); 17 int idx = kmp_search(strA, strB); 18 return idx != -1; 19 } 20 21 string pre_serial(TreeNode* root){ 22 if(root==NULL) return "#!"; 23 string res = std::to_string(root->val)+"!"; 24 res += pre_serial(root->left); 25 res += pre_serial(root->right); 26 return res; 27 } 28 29 int kmp_search(string s, string p){ 30 int len_s=s.length(), len_p=p.length(); 31 int* next = getNext(p); 32 int i=0, j=0; 33 while(i<len_s && j<len_p){ 34 if(s[i] == p[j] || j==-1){ 35 ++i; 36 ++j; 37 }else{ 38 j = next[j]; 39 } 40 } 41 return j==len_p ? i-j : -1; 42 } 43 44 int* getNext(string p){ 45 int len = p.length(); 46 int* next = new int[len]; 47 next[0] = -1; 48 49 int k=-1, j=0; 50 while(j<len-1){ 51 if(k==-1 || p[j]==p[k]){ 52 if(p[j+1] == p[k+1]) 53 next[++j] = next[++k]; 54 else 55 next[++j] = ++k; 56 }else 57 k = next[k]; 58 } 59 return next; 60 } 61 };
2. 詞語變形題
對於兩個字符串A和B,如果A和B中出現的字符種類相同且每種字符出現的次數相同,則A和B互為變形詞,請設計一個高效算法,檢查兩給定串是否互為變形詞。
給定兩個字符串A和B及他們的長度,請返回一個bool值,代表他們是否互為變形詞。
思路:C++字符的取值范圍為0-255,Java為0-65535。可以設置一個大小為256的數組,存儲A中出現的每個字符的計數。B同理。然后比較兩個計數數組是否相等。
知識點:字符取值范圍;給定取值范圍時,可用數組模擬哈希表,效率更高。

1 class Transform { 2 public: 3 bool chkTransform(string A, int lena, string B, int lenb) { 4 int* cntA=new int[256](); 5 int* cntB=new int[256](); 6 for(int i=0; i<lena; ++i) 7 ++cntA[A[i]]; 8 for(int i=0; i<lenb; ++i) 9 ++cntB[B[i]]; 10 for(int i=0; i<256; ++i) 11 if(cntA[i] != cntB[i]) 12 return false; 13 return true; 14 } 15 };
3. 判斷串的旋轉
如果對於一個字符串A,將A的前面任意一部分挪到后邊去形成的字符串稱為A的旋轉詞。比如A="12345",A的旋轉詞有"12345","23451","34512","45123"和"51234"。對於兩個字符串A和B,請判斷A和B是否互為旋轉詞。
給定兩個字符串A和B及他們的長度lena,lenb,請返回一個bool值,代表他們是否互為旋轉詞。
思路:令C=A+A, 然后在C中用KMP算法查找子串B。
4. 句子的逆序
給定一個原字符串A和他的長度,請返回逆序后的字符串。如輸入:"dog loves pig",13,返回:"pig loves dog"。
思路:實現一個逆序函數,然后對整個句子逆序,然后對單詞逆序。
5. 最大回文子串 LeetCode 5

1 class Solution { 2 public: 3 string longestPalindrome(string s) { 4 int len = 0; 5 string str; 6 // 遍歷每一個位置,作為中心點 7 for(int i=0; i<s.size(); ++i) 8 { 9 // 查找aba模式回文串 10 for(int j=0; i-j>=0 && i+j<s.size(); ++j) 11 if(s[i-j] == s[i+j]) 12 { 13 if(2*j+1 > len) 14 { 15 str = s.substr(i-j, 2*j+1); 16 len = 2*j+1; 17 } 18 } 19 else break; 20 // 查找abba模式回文串 21 for(int l=i,r=i+1; l>=0&&r<s.size(); --l,++r) 22 if(s[l] == s[r]) 23 { 24 if(r-l+1 > len) 25 { 26 str = s.substr(l, r-l+1); 27 len = r-l+1; 28 } 29 } 30 else break; 31 } 32 return str; 33 } 34 };