编程题 回文串难题

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


 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值