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