编程题 回文串难题

来源:互联网 发布:淘宝服装平铺拍照技巧 编辑:程序博客网 时间:2024/06/12 07:15

1、寻找字符串的最长回文子串  Longest Palindrome

(1)动态规划的方法
状态转移:dp[i][j]与dp[i+1][j-1]有关,如果dp[i+1][j-1]==true,并且A[i]==A[j],则dp[i][j]==true,单字符是true,双字符直接比较A[i]==A[j]。同时,需要注意的是初始化的dp[n][n]不能保证是初始化为false,需要在循环时确保false的情况。

class Solution {public:    string longestPalindrome(string A) {        int n=A.size();        if(n<=1) return A;        int sum=1;        bool dp[n][n];//这里并没有让他全部初始化为false        for (int i = 0; i < n; ++i) {            dp[i][i] = true;        }        int left=0,right=0;        for(int i=n-1;i>=0;i--)            for(int j=i+1;j<n;j++)                {                if(A[i]==A[j]&&(i+1==j||dp[i+1][j-1]))                {                    dp[i][j]=true;                    if(sum<j-i+1){                        sum=j-i+1;                        left=i;                        right=j;                    }                                }                else dp[i][j]=false;                    }        return A.substr(left,right-left+1);    }};
(2)中心拓展方法

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都是移到了回文串的外围位置    }      };

2、回文字符串划分  131. Palindrome Partitioning

题目描述:
将一个字符串划分成回文字串,返回所有的划分结果
分析:
从左到右,当找到一个回文字串时,递归下去,直到字符串的末尾,把得到的串加到结果上。递归后置pop操作。是通常的回溯结构

class Palindrome{public:        /*131. Palindrome Partitioning    Given a string s, partition s such that every substring of the partition is a palindrome.Return all possible palindrome partitioning of s.For example, given s = "aab",Return[  ["aa","b"],  ["a","a","b"]]*/ public:    vector<vector<string>> partition(string s) {        vector<vector<string>> res;        vector<string> curStr;        doPartition(s,0,s.size(),curStr,res);        return res;    }    void doPartition(string& s,int left,int length,vector<string>& curStr,vector<vector<string>>& res){        if(left==length)            {                res.push_back(curStr);                return ;            }            for(int i=left;i<length;i++)            {                if(isPalindrome(s,left,i))                {                    curStr.push_back(s.substr(left,i-left+1));//注意substr的写法                    doPartition(s,i+1,length,curStr,res);                    curStr.pop_back();                }            }            }    bool isPalindrome(string& s,int left,int right){        if(left==right)            return true;        while(left<=right)        {            if(s[left++]!=s[right--])                return false;        }        return true;    }};

3、回文字符串划分  Palindrome Partitioning II  程序员代码面试 回文最少分割数

题目:
将一个字符串划分成回文子串,要求返回最少的划分次数
思路:
参考程序员代码面试指南
用dp[i]表示str[i----length-1]的最少划分数,而dp[i]取决于从i开始的第一个 这个题目与第一个题目类似
   int minCut(string s) {        int n=s.size();        vector<int> dp(n+1,numeric_limits<int>::max());//从i到n-1的最少分割数,结果返回dp[0]        dp[n]=-1;//这个很巧妙        vector<vector<int>> p(n,vector<int>(n,0));//p[i][j]表示从i-j是否是回文串        for(int i=n-1;i>=0;i--)        {            for(int j=i;j<n;j++)        {            if(s[i]==s[j]&&(j-i<2||p[i+1][j-1]==1)) {                    p[i][j]=1;                    dp[i]=min(dp[i],1+dp[j+1]);//注意时j+1很巧妙            }        }        }                    return dp[0];    }

4、最长回文子序列 516. Longest Palindromic Subsequence

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])
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;                                    dp[i][j]=max(dp[i][j],max(dp[i+1][j],dp[i][j-1]));              }           }          return dp[0][n-1];                    }  };  

5、回文子串的个数  647. Palindromic Substrings

这道题与1一样,也是设置dp[][] 布尔矩阵,只是,在循环过程中统计true出现的次数
class Solution {public:    int countSubstrings(string A) {        int n=A.size();        if(n<=1) return n;        int sum=0;        bool dp[n][n];//这里并没有让他全部初始化为false        for (int i = 0; i < n; ++i) {            dp[i][i] = true;            sum++;        }        int left=0,right=0;        for(int i=n-1;i>=0;i--)            for(int j=i+1;j<n;j++)                {                if(A[i]==A[j]&&(i+1==j||dp[i+1][j-1]))                {                    dp[i][j]=true;                   sum++;                                }                else dp[i][j]=false;                    }        return sum;    }};


 





原创粉丝点击