转换到回文字符串

given a word,convert it into a pallindrome with minimum addition of letters to it.letters can be added anywhere in the word.for eg if yahoo is given result shud be yahoohay.give a optimize soln


对于题目要多考虑其本身的特殊性质

回文字符串,首尾相同

方法1:

设原字符串是st1

源字符串的反转串是str2

st1和str2的最长公共子序列是st3


接下来就是st1,str2,str3归并的过程。


char* CalcLCS(const char* szStr1, const char* szStr2, char pOut[])
{
        assert(szStr2 && szStr1 && pOut);
        int nLen1 = strlen(szStr1);
        int nLen2 = strlen(szStr2);

        if (nLen1 == 0 || nLen2 == 0)
        {
                pOut[0] = 0;
                return pOut;
        }

        int** pDP = new int*[nLen1];
        for (int i = 0; i < nLen1; i++)
                pDP[i] = new int[nLen2];

        //initialize
        bool bMatch = false;
        for (int i = 0; i < nLen2; i++)
        {
                if (bMatch || szStr2[i] == szStr1[0])
                {
                        bMatch = true;
                        pDP[0][i] = 1;
                }
        }

        bMatch = false;
        for (int i = 0; i < nLen1; i++)
        {
                if (bMatch || szStr1[i] == szStr2[0])
                {
                        bMatch = true;
                        pDP[i][0] = 1;
                }
        }

        //Calculate lcs length
        for (int i = 1; i < nLen1; i++)
        {
                for (int j = 1; j < nLen2; j++)
                {
                        if (szStr1[i] == szStr2[j])
                                pDP[i][j] = pDP[i-1][j-1] + 1;
                        else
                                pDP[i][j] = pDP[i-1][j] > pDP[i][j-1] ? pDP[i-1][j] : pDP[i][j-1];
                }
        }

        //put string to pOut
        int nLCSLen = pDP[nLen1-1][nLen2-1];
        int nIter = nLCSLen;
        pOut[nIter--] = 0;

        int x = nLen1-1;
        int y = nLen2-1;
        while (nIter >= 0)
        {
                if (0 == x)
                {
                        pOut[0] = szStr1[0];
                        break;
                }

                if (0 == y)
                {
                        pOut[0] = szStr2[0];
                        break;
                }

                if (pDP[x][y] == pDP[x-1][y-1]+1 && szStr1[x] == szStr2[y])
                {
                        pOut[nIter--] = szStr1[x];
                        x--,y--;
                }
                else if (pDP[x-1][y] == pDP[x][y])
                        x--;
                else y--;
        }

        for (int i = 0; i < nLen1; i++)
                delete []pDP[i];
        delete []pDP;

        return pOut;
}

char* TurnToPallindrome(const char* szStr, char pOut[])
{
        int nLen = strlen(szStr);
        char* pLCS = new char[nLen+1];
        char* pReverse = new char[nLen+1];

        pReverse[nLen] = 0;
        int nIter = 0;
        for (int i = nLen-1; i >= 0; i--)
                pReverse[nIter++] = szStr[i];

        CalcLCS(szStr, pReverse, pLCS);

        //three way merge
        const char* p1 = szStr;
        const char* p2 = pLCS;
        const char* p3 = pReverse;
        char* pWrite = pOut;
        
        while (*p2 != 0)
        {
                if (*p1 != *p2)
                {
                        *pWrite++ = *p1++;
                        continue;
                }

                if (*p3 != *p2)
                {
                        *pWrite++ = *p3++;
                        continue;
                }

                *pWrite++ = *p2++;
                p1++,p3++;
        }
        
        while (*p1 != 0) *pWrite++ = *p1++;
        while (*p3 != 0) *pWrite++ = *p3++;

        *pWrite = 0;

        delete []pLCS;
        delete []pReverse;

        return pOut;
}

方法2:

如果只让求最少的插入元素的个数,用动态规划,但是要生成回文就比较麻烦了

设f[i][j]表示从i开始的长度为j的字符串变成回文,最小需要插入的元素个数。

如果a[0] = a[n-1]

f[0][n] = f[1][n-2]

否则

f[0][n] = 1 + min(f[0][n-1], f[1][n-1])

#define MAXL 1010
char s[MAXL];
int dp[MAXL][MAXL];
int getPath(int p, int l, char *ans)
{
        if(l < 2) {
                if(l) *ans = s[p];
                return l;
        }
        if(s[p] == s[p+l-1]) {
                *ans = s[p];
                return 1+getPath(p+1, l-2, ans+1);
        } else if(dp[p][l] == 1+dp[p+1][l-1]) {
                *ans = s[p];
                return 1+getPath(p+1, l-1, ans+1);
        } else {
                *ans = s[p+l-1];
                return 1+getPath(p, l-1, ans+1);
        }
}
int main() 
{
        char ans[MAXL*2];
        cin >> s;
        int i, j, l = strlen(s);
        for(i = 2; i <= l; i++)
                for(j = 0; j <= l-i; j++) {
                        if(s[j] == s[j+i-1])
                                dp[j][i] = dp[j+1][i-2];
                        else
                                dp[j][i] = 1+min(dp[j+1][i-1], dp[j][i-1]);
                }
        cout << dp[0][l] << endl;
        int len = getPath(0, l, ans);
        ans[l+dp[0][l]] = 0;
        for(i = l+dp[0][l]-1; i >= len; i--)
                ans[i] = ans[l+dp[0][l]-i-1];
        cout << ans << endl;
        return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值