leetcode 5最长回文子串(动态规划 DP)(c语言)

在讲动态规划题目之前,我先写一段有关对动态规划的一些定义,希望能帮助那些没有了解过动态规划的同学一些基本的知识,这样能更好的理解代码的意图和背后的思路。

动态规划

一、定义
动态规划(Dynamic Programming,DP)是的一个分支,是求解决策过程最优化的过程。20世纪50年代初,美国数学家贝尔曼(R.Bellman)等人在研究多阶段决策过程的优化问题时,提出了著名的最优化原理,从而创立了动态规划。
二、思想原理
只要我们能够把问题看成多阶段决策问题皆可以运用动态规划的思想来解决问题。或者说我们想要求解最优解时,也可以联想到动态规划思想。
对于确定性的决策过程。问题中下一段的状态已由当前段的状态及决策完全确定。运用动态规划一个大前提是要所面临的当前问题只是由前面的决策所决定,并不被后面的决策所影响。还有一点当我们看当问题中的重复子问题时,可以试图利用动态规划的思想解题。
三、解题技巧
想要写出动态规划问题的代码,关键有两个点:
1.能写出完整的状态转移方程
2.能够解决边界初始化

为什么动态规划的思想会是的问题比较简单,因为我们找到了其中的重叠子问题,然后解决每一个重叠子问题都满足这一个状态转移方程,利用前面已经解决的问题,来解决后面待解决的问题,空间换时间降低了时间复杂度,更重要的时,动态规划的这一种思想理念是解题的一种好方法。

—————————————————————————————————接下来是题解:
LeetCode: 5 最长回文子串
题目描述:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例2:

输入: "cbbd"
输出: "bb"

先直接上代码:(尝试用动态规划的思想理解代码)

char* longestPalindrome(char* s) {
    if (s[0] == 0)
        return s;
    int i, j, len, max = 0, m, n, k = 0, x;
    len = strlen(s);
    if (len < 2)
        return s;
    char* sta = (char*)malloc(sizeof(char) * (len + 1));
    int** dp = (int**)malloc(sizeof(int*) * len);
    for (i = 0; i < len; i++)
        dp[i] = (int*)malloc(sizeof(int) * len);
    for (i = 0; i < len; i++)
        dp[i][i] = 1;
    for (j = 1; j < len; j++)
        for (i = 0; i < j; i++)
        {
            if (s[i] != s[j])
                dp[i][j] = 0;
            else
            {
                if (j - i < 3)
                    dp[i][j] = 1;
                else
                    dp[i][j] = dp[i + 1][j - 1];
            }
        }
    for(i=0;i<len;i++)
        for(j=i;j<len;j++)
    if (dp[i][j] && j - i + 1 > max)
    {
        max = j - i + 1;
        m = i;
        n = j;
    }
    for (x = m; x <= n; x++)
    {
        sta[k] = s[x];
        k++;
    }
    sta[k] = 0;
    return sta;
}

思路:首先我先明确解题思路。很明显这是一个求解最优解的问题。最优解就是最长的回文子串。然后我们构思求解所需要的状态数组。我们这里用的是一个二维状态数组dp。
而在这一题中,我们并没有用一维dp数组来表示当前的最长回文子串的长度。我们用的是二维数组来表示从i->j之间的这段子串是否是回文子串,我们的状态是真与假,而不是长度。这一点很重要。
然后明确了状态数组所表示的状态,我们接下来就是要做的是写出完整的状态转移方程。要写出状态转移方程,要我们根据我们明确的状态来一步一步推导。在推导的开始我们会根据情况的复杂程度来分情况来讨论对应的状态转移。
首先我们会考虑的存在两种情况:
s[i]=s[j]时,这时候我们会想到dp[i][j]取决于dp[i+1][j-1];(j>i)
如果s[i]!=s[j]时,那么很简单dp[i][j]=false。

那么这就是大概的一个转移方程,当然,要写出完整无误的状态转移方程的话,还要注意其中的小细节。接下来就是边界的初始化了。
很显然这里的主要放生转移的方程是dp[i][j]=dp[i+1][j-1] 所以容易得出边界的初始化是dp[i][i]=true;

这里还有一个值得一提的地方是:

for (j = 1; j < len; j++)
        for (i = 0; i < j; i++)

这里循环,我一开始习惯性的写了这个:

for (i = 0; i < len; i++)
        for (j = i + 1; j < len; j++)

后来才察觉这样写是不行的,下一段的状态已由当前段的状态及决策完全确定这一原则,这里就体现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值