1. 程式人生 > >最長公共子串、最長公共子序列、最長迴文子串、最長迴文子序列、迴文子串個數

最長公共子串、最長公共子序列、最長迴文子串、最長迴文子序列、迴文子串個數

1、最長公共子串

首先看最長公共子串的解答(暴力演算法、動態規劃、)
從優化到再優化,最長公共子串

2、最長公共子序列(LCS) 

3、 leetcode 5 Longest Palindromic Substring 最長迴文串

方法1:藉助最長公共子串問題,將原來的string翻轉,求兩個字串的最長公共子串,但是可能出現的情況是S=”abacdfgdcaba”S' = \textrm{''abacdgfdcaba''}S方法2:暴力演算法
調出所有的子串比較是否是迴文串
方法3: 動態規劃
P(i,j)P(i,j) as following:P(i,j)={true,false,

if the substring SiSj is a palindromeotherwise.true,false,if the substring SiSj is a palindromeotherwise.P(i, j) = ( P(i+1, j-1) \text{ and } S_i == S_j )P(i,j)=(P(i+1,j1) and Sii
==Sjj
)P(i, i) = trueP(i,i)=trueP(i, i+1) = ( S_i == S_{i+1} )P(i,i+1)=(Sii
==Si+1i+1

)事件複雜度和空間複雜度都是n2
方法4: 自中心擴充套件 沒有動態規劃陣列,時間複雜度仍然是n2,空間複雜度是1
每個字串都有一箇中心,一共有2n-1箇中心。迴文串是偶數的時候,中心在兩個字元之間

class Solution {
public:
    string longestPalindrome(string s) {
        //使用第四個方法,自中心擴充套件
        int start=0,end=0;//儲存當前最長迴文串的起始和終結位置
        for(int i=0;i<s.size();i++)
        {
            int len1=expandFromCenter(s,i,i);//以當前字元為中心的迴文串(奇數)
            int len2=expandFromCenter(s,i,i+1);//以當前和下一個字元的中間為中心的迴文串(偶數)
            int len=max(len1,len2);
            if(len>end-start+1)//如果求得的新字串長度是比之前儲存的要長的話
            {
                 start=i-(len-1)/2;
                end=i+len/2;
            }
        }
        return s.substr(start,end-start+1);//注意這個函式的用法,是首地址和字串的長度
    }
    int expandFromCenter(string& s,int left,int right){
        while(left>=0&&right<=s.size()&&s[left]==s[right]){//這種書寫方式考慮到奇數和偶數的情況
            --left;
            ++right;
        }
        return right-left-1;//返回長度,因為right和left都是移到了迴文串的外圍位置
    }      
};
馬拉車演算法: 516. Longest Palindromic Subsequence 最長迴文子序列 dp演算法: dp[i][j]指的是i,j之間的最大回文子序列 有:

if i == j, then longest[i][j] = 1, naturally
if i+1 == j, then longest[i][j] = 2 if s[i] == s[j]
longest[i][j] = 1 otherwise
Transition rule:

  1. s[i] == s[j]
    dp[i][j] = max(dp[i+1][j], dp[i][j-1], dp[i+1][j-1] + 2)
  2. s[i] != s[j]
    dp[i][j] = max(dp[i+1][j], dp[i][j-1], dp[i+1][j-1])
注意:循環的時候要注意次序,外迴圈是字串的長度(從1到n),內迴圈是起始位置,這樣才能保證迭代公式中的值都是更新後的。
class Solution {
public:
    //lhs means left hand side, rhs means right hand side
    int longestPalindromeSubseq(string s) {
        if (s.empty()) return 0;
        
        vector<vector<int>> longest(s.size(), vector<int>(s.size()));
        for (int len=1; len<=s.size(); len++) {
            for (int lhs=0; lhs+len<=s.size(); lhs++) {
                int rhs = lhs+len-1;
                if (lhs == rhs) {
                    longest[lhs][rhs] = 1;
                } else if (lhs+1 == rhs) {
                    longest[lhs][rhs] = (s[lhs] == s[rhs]) ? 2 : 1;
                } else {
                    int add = s[lhs] == s[rhs] ? 2 : 0;
                    longest[lhs][rhs] = max(max(longest[lhs][rhs-1], longest[lhs+1][rhs]), longest[lhs+1][rhs-1] + add);
                }
            }
        }
        
        return longest[0].back();
    }
};
另外一種迴圈方式:
class Solution {
public:
    int longestPalindromeSubseq(string s) {
       int n=s.size();
        vector<vector<int>> dp(n,vector<int>(n,0));
        for(int i=n-1;i>=0;i--)
        {
            dp[i][i]=1;
           for(int j=i+1;j<n;j++)
            {
                if(s[i]==s[j])
                    dp[i][j]=dp[i+1][j-1]+2;
               else
                   dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
            } 
        }
        return dp[0][n-1];
            
    }
};

647. Palindromic Substrings 統計迴文子串的個數

Given a string, your task is to count how many palindromic substrings in this string.

The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters.

Example 1:

Input: "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".

Example 2:

Input: "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".

Note:

  1. The input string length won't exceed 1000.
自己的解法:與516類似
class Solution {
public:
    int countSubstrings(string s) {
        int sum=0;
        int n=s.size();
        if(n==0) return 0;
        vector<vector<bool>> dp(n,vector<bool>(n,false));
        for(int i=n-1;i>=0;i--)
        {
            dp[i][i]=true;
            sum++;
            for(int j=i+1;j<n;j++)
            {
                if(s[i]==s[j])
                {
                    if(i+1==j||dp[i+1][j-1])
                    {
                        dp[i][j]=true;
                        sum++;
                    }
                }
                else dp[i][j]=false;
            }
        }
        return sum;
    }
};

214. Shortest Palindrome 最短迴文串
給定一個字串,在它前面新增字元,組成一個最短的迴文串

Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.

For example:

Given "aacecaaa", return "aaacecaaa".

Given "abcd", return "dcbabcd".

使用KMP演算法 放一放 其他相關: 242. Valid Anagram

Given two strings s and t, write a function to determine if t is an anagram of s.

For example,
s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.

Note:
You may assume the string contains only lowercase alphabets.

Follow up:
What if the inputs contain unicode characters? How would you adapt your solution to such case?

class Solution {
public:
    bool isAnagram(string s, string t) {
        vector<int> flag(256,0);
        if(s.size()!=t.size()) return false;
        for(int i=0;i<s.size();i++)
            flag[s[i]]++;
        for(int i=0;i<s.size();i++)
        {
            if(flag[t[i]]==0) return false;
            flag[t[i]]--;
        }
        if(find_if(flag.begin(),flag.end(),com)!=flag.end()) return false;
        return true;
    }
    static bool com(const int s){
        return s>0?true:false;
    }
};
classSolution {public:boolisAnagram(string s,string t){if (s.length() != t.length()) returnfalse;int n = s.length(); unordered_map<char,int> counts; for (int i = 0; i < n; i++) { counts[s[i]]++; counts[t[i]]--; } for (auto count : counts) if (count.second) returnfalse;returntrue; }};