LeetCode 回文子串

5. 最长回文子串

题目描述:

解法一(暴力求解):

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        string res;
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                string temp=s.substr(i,j-i+1),rev=temp;
                reverse(rev.begin(),rev.end());
                if(temp==rev&&temp.size()>res.size())
                    res=temp;
            }
        }
        return res;
    }
};

class Solution {
public:
    string longestPalindrome(string s) {
        string res;
        string str;
        for(int i=0;i<s.size();i++){
            for(int j=i;j<s.size();j++){
                str+=s[j];
                string rev=str;
                reverse(rev.begin(),rev.end());
                if(str==rev&&str.size()>res.size())
                    res=str;
            }
            str="";
        }
        return res;
    }
};


class Solution {
public:
    bool isPalindrome(string s){
        int len=s.size();
        for(int i=0;i<len/2;i++){
            if(s[i]!=s[len-i-1])
                return false;
        }
        return true;
    }
    string longestPalindrome(string s) {
        int n=s.size();
        string res;
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                string temp=s.substr(i,j-i+1);
                if(isPalindrome(temp)&&temp.size()>res.size())
                    res=temp;
            }
        }
        return res;
    }
};

超时了!

解法二(最长公共子串):

class Solution {
public:
    bool isPalindrome(string s) {
        int len = s.size();
        for (int i = 0; i<len; i++) {
            if (s[i] != s[len - i - 1])
                return false;
        }
        return true;
    }
    string longestPalindrome(string s) {
        string res;
        string rev = s;
        reverse(rev.begin(), rev.end());
        if(s==rev) return s;
        for (int i = 0; i<s.size(); i++) {
            for (int j = i; j<s.size(); j++) {
                string temp = s.substr(i, j - i + 1);
                if(res.size()>=temp.size()) continue;
                else if (rev.find(temp)!=string::npos ){
                     if(isPalindrome(temp)) {
                        res = temp;
                     }
                }
                else break;
            }
        }
        return res;
    }
};

class Solution {
public:
    string longestPalindrome(string s) {
        string res;
        string rev = s;
        reverse(rev.begin(), rev.end());
        if(rev==s) return s;
        string temp;
        for (int i = 0; i<s.size(); i++) {
            for (int j = i; j<s.size(); j++) {
                temp += s[j];
                if (res.size()>=temp.size())
                    continue;
                else if(rev.find(temp)!=string::npos){
                    string q=temp;
                    std::reverse(q.begin(),q.end());
                    if(q==temp)
                        res=temp;
                }
                else break;
            }
            temp="";
        }
        return res;
    }
};

这种方法已经通过了。

解法三(动态规划):

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.length();
        if(len<2) return s;
        bool dp[len][len];
        memset(dp,0,sizeof(dp));
        string res;
        res+=s[0];                                        //最少一个字符
        for(int i=0;i<len;i++){
            dp[i][i]=1;
            if(i<len-1&&s[i]==s[i+1]){
                dp[i][i+1]=1;
                res=s.substr(i,2);                        //两个字符回文情况
            }
        }
        for(int l=3;l<=len;l++){
            for(int i=0;i<=len-l;i++){
                int j=i+l-1;
                if(s[i]==s[j]&&dp[i+1][j-1]){
                    dp[i][j]=1;
                    if(j-i+1>res.size())
                        res=s.substr(i,j-i+1);
                }
            }
        }
        return res;
    }
};



class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.length();
        if(n<2) return s;
        vector<vector<bool>> dp(n,vector<bool>(n,0));
        int start=0,len=1;
        for(int i=0;i<n;i++){
            dp[i][i]=1;
            if(i<n-1&&s[i]==s[i+1]){
                dp[i][i+1]=1;
                start=i;len=2;
            }
        }
        for(int l=3;l<=n;l++){
            for(int i=0;i+l-1<n;i++){
                int j=i+l-1;
                if(s[i]==s[j]&&dp[i+1][j-1]){
                    dp[i][j]=1;
                    start=i;
                    len=l;
                }
            }
        }
        return s.substr(start,len);
    }
};


class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        string res;
        vector<vector<bool>> dp(n,vector<bool>(n,0));
        for(int i=0;i<n;i++){                                    //开始位置
            for(int j=i;j>=0;j--){                               //中止位置
                if(s[i]==s[j]&&(i-j<2||dp[j+1][i-1]==1)){
                    dp[j][i]=1;
                    if(i-j+1>res.size()) res=s.substr(j,i-j+1);
                }
            }
        }
        return res;
    }
};

解法四(中心扩展):

class Solution {
public:
    int Expand(string& s, int ll, int rr) {
        if (s[ll] != s[rr]) return 1;
        while (s[ll] == s[rr]) {
            if (ll == 0 || rr == s.size() - 1)
                break;
            else {
                ll--;
                rr++;
            }
        }
        return s[ll] == s[rr]? rr - ll + 1: rr - ll-1;
    }

    string longestPalindrome(string s) {
        int n = s.size();
        if (n<2) return s;
        int start = 0, len = 1;
        for (int i = 0; i<n - 1; i++) {
            int lenth1 = Expand(s, i, i);
            int lenth2 = Expand(s, i, i + 1);
            int temp = max(lenth1, lenth2);
            if (len<temp) {
                start = i - (temp - 1) / 2;
                len = temp;
            }
        }
        return s.substr(start, len);
    }
};

解法五(Manacher 算法,马拉车算法):

这是一个专门用作处理最长回文子串的方法,思想很巧妙,比较难以理解,这里直接借用了别人的讲解方法。其实主要思想是,把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串,这个叫中心扩展法,但是这个方法还要考虑到处理 abba 这种偶数个字符的回文串。Manacher 法将所有的字符串全部变成奇数个字符。

有时间研究一下!

214. 最短回文串

题目描述:

解法一(暴力解法):

class Solution {
public:
    string shortestPalindrome(string s) {
        int n=s.size();
        if(n<2) return s;
        int len=1;
        string res;
        string temp;
        for(int i=0;i<n;i++){
            temp+=s[i];
            string rev=temp;
            reverse(rev.begin(),rev.end());
            if(rev==temp)
                len=temp.size();
        }
        res=s.substr(len,n-len);
        reverse(res.begin(),res.end());
        return res+s;
    }
};


class Solution {
public:
    string shortestPalindrome(string s) {
        int n=s.size();
        string rev=s;
        reverse(rev.begin(),rev.end());
        for(int i=0;i<n;i++){
            if(s.substr(0,n-i)==rev.substr(i))
                return rev.substr(0,i)+s;
        }
        return "";
    }
};

超时了!

解法二(双指针减少搜索长度):

class Solution {
public:
    string shortestPalindrome(string s) {
        int n=s.size();
        int i=0;
        for(int j=n-1;j>=0;j--){
            if(s[j]==s[i])
                i++;
        }
        if(i==n)
            return s;
        string revlast=s.substr(i);
        reverse(revlast.begin(),revlast.end());
        return revlast+shortestPalindrome(s.substr(0,i))+s.substr(i);
    }
};

解法三(KMP算法):

KMP算法是一个时间复杂度为 O(n+m) 的字符串匹配算法,其中 n 和 m 分别是待匹配文本和字符串的长度。KMP算法的核心是部分匹配表(查找表)f(s)。

有时间研究一下

336. 回文对

题目描述:

解法:

四种情况:

  1. 数组里有空字符串,并且数组里还有自己就是回文的字符串,每出现一个可与空字符串组成两对。(可并入3,4)
  2. 如果自己的翻转后的字符串也在数组里,可以组成一对,注意翻转后不能是自己。
  3. 如果某个字符串能找到一个分割点,分割点前的部分是回文,后半部分翻转后也在数组里,可组成一对。
  4. 把3反过来,如果后部分是回文,前半部分翻转后在数组里,可组成一对。
class Solution {
public:
    bool isPalindrome(string& s,int i,int j){
        while(i<j){
            if(s[i]!=s[j])
                return false;
            i++;j--;
        }
        return true;
    }
    vector<vector<int>> palindromePairs(vector<string>& words) {
        int n=words.size();
        unordered_map<string,int> mp;        //先把每个字符串对应的位置对应起来
        set<int> lens;                       //用来搜索可以匹配够成回文的串
        vector<vector<int>> res;
        for(int i=0;i<n;i++){
            mp[words[i]]=i;
            lens.insert(words[i].size());
        }
        for(int i=0;i<n;i++){
            int len=words[i].size();
            string rev=words[i];
            reverse(rev.begin(),rev.end());        
            if(mp.count(rev)&&mp[rev]!=i)                    //整个串与其他串构成回文,对应方式2
                res.push_back(vector<int>{i,mp[rev]});
            auto pos=lens.find(len);
            for(auto it=lens.begin();it!=pos;it++){   //串的前段或者后端的一部分与其他串构成回文,其他串长度必然小于当前串
                if(isPalindrome(words[i],0,len-*it-1)&&mp.count(rev.substr(0,*it))){ //两种构成回文的方式  对应方式3
                    res.push_back(vector<int>{mp[rev.substr(0,*it)],i});
                }
                if(isPalindrome(words[i],*it,len-1)&&mp.count(rev.substr(len-*it,*it))){  //对应方式4
                    res.push_back(vector<int>{i,mp[rev.substr(len-*it)]});
                }
            }
        }
        return res;
    }
};

131. 分割回文串

题目描述:

解法一(回溯):

class Solution {
public:
    bool isPalindrome(string& s, int l, int r) {    //判断[l,r]之间是否位回文
        while (l<r) {
            if (s[l++] != s[r--])
                return false;
        }
        return true;
    }
    void helper(vector<vector<string>>& res, string& s, int ll, int rr, vector<string>& temp) {
        if (ll == rr) res.push_back(temp);
        for (int len = 1; len <= rr - ll; len++) {        //以长度为标尺,长度扩大
            if (isPalindrome(s, ll, ll + len - 1)) {
                temp.push_back(s.substr(ll, len));
                helper(res, s, ll + len, rr, temp);
                temp.erase(temp.end() - 1);
            }
        }
    }
    vector<vector<string>> partition(string s) {
        vector<vector<string>> res;
        vector<string> temp;
        helper(res, s, 0, s.size(), temp);
        return res;
    }
};

解法二(dfs+回溯):

class Solution {
public:
    void DFS(string& s, vector<vector<string>>& res, vector<string>& temp, vector<vector<bool>>& dp, int index) {
        if (index == s.size()) {
            res.push_back(temp);
        }
        for (int i = index; i<s.size(); i++) {
            if (dp[index][i]) {
                temp.push_back(s.substr(index, i - index + 1));
                DFS(s, res, temp, dp, i + 1);
                temp.pop_back();
            }
        }
    }
    vector<vector<string>> partition(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n, vector<bool>(n, 0));
        for (int i = 0; i<n; i++) {
            for (int j = i; j >= 0; j--) {
                if (s[i] == s[j] && (i - j<2 || dp[j + 1][i - 1]))
                    dp[j][i] = 1;
            }
        }
        vector<vector<string>> res;
        vector<string> temp;
        DFS(s, res, temp, dp, 0);
        return res;
    }
};


class Solution {
public:
    bool dp[1001][1001] = { 0 };
	vector<vector<string>> res;
	vector<string> tmp;
	vector<vector<string>> partition(string s) {
		int l = s.length();
		//两个for循环构造回文串的dp数组
		for (int i = 0; i < l; i++) {
			for (int j = 0; j <= i; j++) {
				if (s[i] == s[j] && (i - j < 2 || dp[j + 1][i - 1]))
					dp[j][i] = 1;
			}
		}
		dfs(0, l, s);
		return res;

	}

	void dfs(int i,int n,string s) {
		if (i == n) res.push_back(tmp);
		for (int j = i; j < n; j++) {
			if (dp[i][j]) {
				tmp.push_back(s.substr(i, j-i+1));
				dfs(j + 1, n, s);
				tmp.erase(tmp.end() - 1);
			}
		}
	}
};

132. 分割回文串 II

题目描述:

解法:

class Solution {
public:
    int minCut(string s) {
        int n=s.size();
        vector<vector<bool>> dp(n,vector<bool>(n,0));
        vector<int> res(n+1,INT_MAX);
        res[0]=-1;
        for(int i=0;i<n;i++){
            for(int j=i;j>=0;j--){
                if(s[i]==s[j]&&(i-j<2||dp[j+1][i-1])){
                    dp[j][i]=1;
                    res[i+1]=min(res[i+1],1+res[j]);
                }
            }
        }
        return res[n];
    }
};

class Solution {
public:
    int minCut(string s) {
        int n=s.size();
        vector<vector<bool>> dp(n,vector<bool>(n,0));
        vector<int> res(n,INT_MAX);
        for(int i=0;i<n;i++){
            for(int j=0;j<=i;j++){
                if(s[i]==s[j]&&(i-j<2||dp[j+1][i-1])){
                    dp[j][i]=1;
                    if(j==0) res[i]=0;
                    else res[i]=min(res[i],1+res[j-1]);
                }
            }
        }
        return res[n-1];
    }
};
原文地址:https://www.cnblogs.com/oneDongHua/p/14263988.html