常見字符串算法題


1. 拓撲結構相同的子樹

對於兩棵彼此獨立的二叉樹A和B,請編寫一個高效算法,檢查A中是否存在一棵子樹與B樹的拓撲結構完全相同,節點取值也要相同。

給定兩棵二叉樹的頭結點AB,請返回一個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 };
View Code
 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 };
View Code

2. 詞語變形題

對於兩個字符串A和B,如果A和B中出現的字符種類相同且每種字符出現的次數相同,則A和B互為變形詞,請設計一個高效算法,檢查兩給定串是否互為變形詞。

給定兩個字符串AB及他們的長度,請返回一個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 };
View Code

3. 判斷串的旋轉

如果對於一個字符串A,將A的前面任意一部分挪到后邊去形成的字符串稱為A的旋轉詞。比如A="12345",A的旋轉詞有"12345","23451","34512","45123"和"51234"。對於兩個字符串A和B,請判斷A和B是否互為旋轉詞。

給定兩個字符串AB及他們的長度lenalenb,請返回一個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 };
View Code

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM