回文子串

16 篇文章 1 订阅
13 篇文章 0 订阅

链接:https://www.nowcoder.com/questionTerminal/003482c395bd41c68082f6adc545a600?toCommentId=3230733
来源:牛客网

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

("回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串。)

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

可用C++,Java,C#实现相关代码逻辑

输入描述:

输入一个字符串S 例如“aabcb”(1 <= |S| <= 50), |S|表示字符串S的长度。

输出描述:

符合条件的字符串有"a","a","aa","b","c","b","bcb"

所以答案:7

示例1

输入

aabcb

输出

7

题目分析:这个题一般人解法就是暴力,把这个大字符串的所有子串都拿出来,然后每个翻转一下,接着统计一下是回文的个数!

比如我一开始就是这么写的:

import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc= new Scanner(System.in);
String str = sc.next();
int sum=0;
for (int i = 0; i < str.length(); i++)
for (int j = i+1; j <=str.length(); j++)
{
String str1=str.substring(i, j);
if(str1.equals( new StringBuffer(str1).reverse().toString()))
sum++;
}
System.out.println(sum);
}
}

两次for循环,按给的例子aabcb举例,第一遍截取出来第一个a开始的子串,分别是a,aa,aab,aabc,aabcb,然后用反转函数反转一下,再判断是否相等!相等回文数就加一,不相等就不管!第二遍就是从第二个a开始截取,截出来a,ab,abc,abcb~~~~剩下的自己看!

算法分析:需要O(n^2)次运算,中间还要有各种函数调用,反转处理,总之感觉是不是有很大优化空间!

接下来就讲中心开花,两边散叶的算法:可以省略很多处理!

首先我们看这样一个字符串caabaa,很明显加粗的那一部分是一个比较大的回文,那这段回文核心在哪里呢?越靠近中间越核心,只要中间不是回文,两边的再相等也白瞎。

所以我们应该怎么判断呢?先判断b两边的两个是不是相等的,如果相等,就是一个回文了(aba),然后我们可以接着判断两边的两个字符是不是相等的,一看相等,又一个回文(aabaa)

那我们怎么办呢?

首先我们遍历这个字符数组,每次拿出来一个,然后先比较两边么?

不!

我们要先往右看,比如aabcb,第一个a是一个回文,aa也是一个回文,如果只比较两边,那aa就不可能计算进去。

所以先往右看,看看是不是有aa,bbbb,ccc这样的,只要有就是一个回文,而且不重复。

比如:aaaa,我们第一个a拿出来,然后可以拿出来a,aa,aaa,aaaa这4个

                                 第二个a拿出来,然后可以拿出来a,aa,aaa,这三个!有人一看,这不很多重复了吗?

其实不是的,我们再看看拿出来的这几个:aaaa,aaaa,aaaa,aaaa

                                                                            aaaa,aaaa,aaaa  

看黑色部分,哪里重复了!

找完了这种长得一样的接下来,就要左右开工了,看左右两边是不是相等,比如aabcb,我们找到c这里,然后右找,没找到第2个c,接下来就找这个c的两边,如果相等就多一个回文,然后继续两边找,不相等就break掉。

这样就完了么?

这里有个坑!

比如aabcccb(有个c标黑了)

我们找到了标黑的c那里,先往后找了一个c,回文数+1。再往后找,不符合条件了,然后左右开工,找到一个ccc(aabcccb),回文数又加1~~

这里的ccc我们在找aabcccb(有个c标黑了),从标黑的c那找相同的时候,就会已经找到过ccc(aabcccb)了。

所以,我们要在找到相同的c的时候,记录下最后一个c的位置,然后我们再去左右开工!

不超过这个标记的时候,相等也不加到里面,不相等就break;

比如aabcccb,左右开工俩c(aabcccb)相等,不用增加回文数,但是要继续,接着俩b(aabcccb)相等,且后面那个b位置比标记的c(aabcccb)位置数更大,回文加一。

这样就可以计算完所有回文了!代码如下:

import java.util.*;
 public class Main {
	 public static void main(String[] args){
		Scanner sc= new Scanner(System.in);
		String[] str = sc.next().split("");
		int sum=str.length;
		for (int i = 0; i < str.length; i++) 
			{
			int j=i+1;
			while (j <str.length)//右看
			{
				if (str[i].equals(str[j]))
					{
					sum++;	
					j++;
					}
				else
					break;
			}			
			int m=i-1;
			int n=i+1;
			while (m>=0 && n<str.length)//左看
			{
				if (str[m].equals(str[n])&&n>=j)
					{
					sum++;	
					m--;
					n++;
					}
				else
					break;
			}
		}
		System.out.println(sum);
	 }	
} 

开开心心跑一下!o(∩_∩)o 哈哈

神马Σ(っ °Д °;)っ ?只AC了80%

好吧,还有一个坑!

那就是出现abba这种情况的时候,刚刚的算法没考虑里面是偶数个b这种情况,所以~~~

那就在向右看完了,就在原有基础上直接左右开工!直接解决掉中间是偶数个的问题!

再上代码:AC100%

import java.util.*;
 public class Main {
	 public static void main(String[] args){
		Scanner sc= new Scanner(System.in);
		String[] str = sc.next().split("");
		int sum=str.length;
		for (int i = 0; i < str.length; i++) 
			{
			int j=i+1;
			while (j <str.length)//右看
			{
				if (str[i].equals(str[j]))
					{
					sum++;	
					j++;
					}
				else
					break;
			}
			int k=i-1;
			while (k>=0&&j <str.length)//右看补加
			{
				if (str[k].equals(str[j]))
					{
					sum++;	
					k--;
					j++;
					}
				else
					break;
			}
			int m=i-1;
			int n=i+1;
			while (m>=0 && n<str.length)//左看
			{
				if (str[m].equals(str[n])&&n>=j)
					{
					sum++;	
					m--;
					n++;
					}
				else
					break;
			}
		}
		System.out.println(sum);
	 }	
} 

跑的还挺快!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值