题解 | #最长回文子序列#

最长回文子序列

http://www.nowcoder.com/practice/c7fc893654b44324b6763dea095ceaaf

最长回文子序列

问题描述:给定一个字符串,找到其中最长的回文子序列,并返回该序列的长度。字符串长度<=5000
示例
输入:"abccsb"
返回值:4
说明:子序列bccb回文序列为bccb,因此最长的回文子序列长度为4

方法一

思路分析

     最长回文子序列表示子序列在给定的序列中位置可以是不连续的。使用递归的办法,采用自上而下的办法,要求的string[0,n-1]中开始元素到末尾元素中间的最长回文子序列,有如下递归方程:
  • 设置$lps(string ,i,j)$表示字符串string中第i个位置到第j个位置中的最长回文子序列
  • 设置$lps(string ,i,j)=1,i=j$,同时这也是递归结束的条件
  • 如果首尾元素相同,那么$lps(string ,i,j)=lps(string ,i+1,j-1)+2$
  • 如果首尾元素不同,那么$lps(string ,i,j)=max\{ lps(string ,i+1,j),lps(string ,i,j-1)\}$

图解

输入:"abccsb",递归过程如下图:
0 1 2 3 4 5
a b c c s b



C++核心代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string 一个字符串由小写字母构成,长度小于5000
     * @return int
     */
    int longestPalindromeSubSeq(string s) {
        // write code here
        int n=s.size();
        return lps(s,0,n-1);
    }
    int lps(string str, int i, int j)
   {
	if (i == j)    
		return 1;	//只有一个元素,回文长度为1
	if (i > j) return 0;   //因为只计算序列str[i....j]
 
	//如果首尾相同
	if (str[i] == str[j])
		return lps(str, i + 1, j - 1) + 2;
	//如果首尾不同
	return max(lps(str, i, j - 1), lps(str, i + 1, j));
    }

};

复杂度分析

  • 时间复杂度:有许多相同的子问题会被重复计算,这是递归的一个问题,递归的时间复杂度为递归的次数*每次递归的操作次数,递归次数为$n^2$,因此时间复杂度为$O(n^2)$,该方***超时
  • 空间复杂度:递归的空间复杂度为递归的深度*每次递归创建的变量,递归深度为$n$,每次递归的空间复杂度为$O(1)$,因此空间复杂度为$O(n)$

方法二

思路分析

     在使用递归的方法时由于采用自上而下的办法,因此有些子问题被重复计算,为了避免这种问题,我们还可以采用自下而上的办法,即采用动态规划的办法,即借助一个二维数组dp[i][j]存储已经计算过的子问题,即第i个位置到第j个位置最长回文子序列的长度。使用动态规划的转移方程为:
  • 所有连续的长度为i+1的子串,$str[j..j+i]$
  • 如果$dp[i][i]=1 i=j$
  • 如果首尾元素相同那么$dp[j][j+i]=dp[j+1][j+i-1]+2$
  • 如果首尾元素不同那么$dp[j][j+i]=max\{dp[j+1][j+i],dp[j][j+i-1]\}$
  • 最后输出$dp[0][n-1]$即为给定字符串的最长回文子串

C++核心代码

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param s string 一个字符串由小写字母构成,长度小于5000
     * @return int
     */
    int longestPalindromeSubSeq(string s) {
        // write code here
        int n=s.size();
        return lpsDp(s,n);
    }
    int lpsDp(string str, int n)
    {
	int  tmp;
    vector<vector<int>> dp(n,vector<int>(n,0));
	for (int i = 0; i < n; ++i) 	
        dp[i][i] = 1;
	for (int i = 1; i < n; ++i)
	{
		tmp = 0;
		//考虑所有连续的长度为i+1的子串,str[j....j+i]
		for (int j = 0; j + i < n; j++)
		{
			if (str[j] == str[j + i])//如果首尾相同
				tmp = dp[j + 1][j + i - 1] + 2;
			else //如果首尾不同
				tmp = max(dp[j + 1][j + i], dp[j][j + i - 1]);
			dp[j][j + i] = tmp;
		}
	}
	return dp[0][n - 1]; //返回字符串str[0...n-1]的最长回文子序列长度
}
};

复杂度分析

  • 时间复杂度:内外层循环次数为$1+2+3+...+n=n*(n+1)/2$,因此时间复杂度为$O(n^2)$
  • 空间复杂度:借助于一个二维数组存储当前位置的最长回文子序列长度,空间复杂度为$O(n^2)$


方法三

思路分析

      为进一步减小空间的使用,在方法二中可以发现求解$dp[i][j]$数组只与相邻状态有关,因此可以设置一个一维的数组。

python核心代码

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param s string 一个字符串由小写字母构成,长度小于5000
# @return int
#
class Solution:
    def longestPalindromeSubSeq(self , s ):
        # write code here
        dp = [1] * len(s)
        for i in range(len(s)-1, -1, -1):
            pre = 0      # dp[i+1][j-1]
            for j in range(i+1, len(s)):
                temp = dp[j]
                if s[i] == s[j]:
                    dp[j] = pre + 2
                else:
                    dp[j] = max(dp[j], dp[j-1])
                pre = temp
        return dp[-1]

复杂度分析

  • 时间复杂度:内外层循环次数为$1+2+3...+n=n*(n+1)/2$,因此时间复杂度为$O(n^2)$
  • 空间复杂度:借助于一个一维数组,空间复杂度为$O(1)$



全部评论

相关推荐

会飞的猿:我看你想进大厂,我给你总结一下学习路线吧,java语言方面常规八股要熟,那些java的集合,重点背hashmap八股吧,jvm类加载机制,运行时分区,垃圾回收算法,垃圾回收器CMS、G1这些,各种乐观锁悲观锁,线程安全,threadlocal这些。在进阶一些的比如jvm参数,内存溢出泄漏排查,jvm调优。我这里说的只是冰山一角,详细八股可以去网上找,这不用去买,都免费资源。mysql、redis可以去看小林coding,我看你简历上写了,你一定要熟,什么底层b+树、索引结构、innodb、mvcc、undo log、redo log、行级锁表级锁,这些东西高频出现,如果面试官问我这些我都能笑出来。消息队列rabbitmq也好kafka也好,学一种就行,什么分区啊副本啊确认机制啊怎么保证不重复消费、怎么保证消息不丢失这些基本的一定要会,进阶一点的比如LEO、高水位线、kafka和rocketmq底层零拷贝的区别等等。计算机网络和操作系统既然你是科班应该理解起来问题不大,去看小林coding这两块吧,深度够了。spring boot的八股好好看看吧,一般字节腾讯不这么问,其他的java大厂挺爱问的,什么循环依赖啥的去网上看看。数据结构的话科班应该问题不大,多去力扣集中突击刷题吧。项目的话其实说白了还是结合八股来,想一想你写的这些技术会给你挖什么坑。除此之外,还有场景题、rpc、设计模式、linux命令、ddd等。不会的就别往简历上写了,虽然技术栈很多的话好看些,但背起来确实累。总结一下,多去实习吧,多跳槽,直到跳到一个不错的中厂做跳板,这是一条可行的进大厂的路线。另外,只想找个小厂的工作的话,没必要全都照这些准备,太累了,重点放在框架的使用和一些基础八股吧。大致路线就这样,没啥太多难度,就是量大,你能达到什么高度取决于你对自己多狠,祝好。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务