Leetcode05-给你一个字符串 s,找到 s 中最长的回文子串。 示例 1: 输入:s = “babad“ 输出:“bab“ 解释:“aba“ 同样是符合题意的答案。 示例 2: 输

题目

给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。

示例 2:

输入:s = “cbbd” 输出:“bb”

示例 3:
输入:s = “a” 输出:“a”

示例 4:

输入:s = “ac” 输出:“a”

提示:
1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

有时间的时候会补充具体思路

一、暴力解法

class Solution {
    
    
    public String longestPalindrome(String s) {
    
    
    int max=1;//存储最大长度,用来判断是否需要改变左右指针
	int left=0;//左指针
	int right=0;//右指针
	//下面为两类特殊情况
	if(s.length()==1)return s;
	else if(s.length()==2) {
    
    
		if(s.charAt(0)==s.charAt(1))
		return s;
		else
			return s.charAt(0)+"";
			}
	//一般情况(数组长度大于2时)		
	for (int i = 1; i < s.length()-1; i++) {
    
    
		int val=1;
		int m=i;int n=i;//m和n是每一次遍历的临时左右指针
		char c=s.charAt(i);
		//注意防止越界,下面是解决```aa```这类特殊情况
		while(++m<s.length()&&s.charAt(m)==c) {
    
    
			val++;
		}
		while(--n>=0&&s.charAt(n)==c) {
    
    
			val++;
		}
		//退出时需要把m、n还原
		m=m==i?m:--m;
		n=n==i?n:++n;
		int mark=0;
		int mark1=0;//后续用mark和mark1是否相等来判断n是否需要+1
		while(++mark>0&&++m<s.length()&&++mark1>0&&--n>=0&&s.charAt(n)==s.charAt(m)) {
    
    
			val+=2;
		}
		//left和right指针是否发生变化
		if(max<val) {
    
    
			max=val;
			right=m-1;
			if(mark1==mark)
			left=n+1;
            else left=n;
		}
	}
	//【left,right】字符串
	 return s.substring(left,right+1);
    }
}
/*         1)s.length<1000,是提示我们o(n²)的时间复杂度是可以的
		 * 2) 需要注意的是:在赋值时,if后面一定要慎重考虑是否有else
		 *  3)在while(++a<5&&--b>0)时,如果 a、b都要在判断时进行变化,一定要注意,如果a不符合, a变b不变,如果b需要用,这时需要添加标志去判断 b是否变化如while(++mark>0&&++a<5&&++mark1>0&&--b>0)
		 * 4)这种求字符串中子字符串的问题,如果该子字符串本身在字符串中连续,最简单的方法当然是找 到left和right指针。
		 *  5)【···aa···】的解决策略
		 */

二、动态规划

用boolean数组dq[i][j]表示字符串中i到j这个子字符串是回文,那么如果dq[i][j]为真,至少s[i]==s[j],其次i+1到j-1字符串也为回文,即dq[i+1][j-1]为真,特殊情况是当真有2个或者3个字符时我们不需要判断内部字符串是否为回文。我们发现,当寻找dq[i][j]时需要dq[i+1][j-1]的结果,也就是这时候j-1需要被我们在遍历j之前遍历,并且[i+1]在[i]之前遍历,决定了外层遍历不能是i,只能是j!(可以看下图帮助理解)代码实现如下:
在这里插入图片描述

class Solution {
    
    
/*
思考:为什么可以去掉判断数组长度为1的情况呢?
	 *因为此使ans[0]和ans[1]都为初始值0,截取下来的字符串为【0,1),所以不用分类讨论*/
    public String longestPalindrome(String s) {
    
    
    int n=s.length();
   int[] ans=new int[2];
   boolean[][] dq=new boolean[n][n];
   int max=1;
   for (int j = 0; j <n; j++) {
    
    
	for (int i = 0; i <j; i++) {
    
    
		dq[i][j]=(s.charAt(i)==s.charAt(j))&&(j-i<3||dq[i+1][j-1]);
		if(dq[i][j]&&max<j-i+1) {
    
    
			max=j-i+1;
			ans[0]=i;
			ans[1]=j;
		}
	}
}
	return s.substring(ans[0],ans[1]+1);	 
	
    }
}

注:很明显,动态规划的逻辑比第一种方法的逻辑要清晰很多,只是可惜在leetcode上运行要300多ms,前一种方法只用了44ms。

猜你喜欢

转载自blog.csdn.net/m0_51801058/article/details/113825385