回文子串-力扣
一、题目:
给你一个字符串 s
,请你统计并返回这个字符串中 回文子串 的数目。
示例1:
输入:s = "abc" 输出:3 解释:三个回文子串: "a", "b", "c"
示例2:
输入:s = "aaa" 输出:6 解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
二、解法:
-
暴力:列举每一个子串,判断是否是回文子串,是的话count+1
-
中心扩展:从里往外扩展至整个字符串,期间是回文子串就count+1
-
读懂例子你就明白具体是怎么实现中心扩展了
例如:aaba 从左到右(扩展即左右两边都需要+1)1.从aaba扩展,由于a处于第1位,得a,则只能够执行一次,使sum + 1
2.从aaba扩展,可得a,aab两个,但是只有a是,则sum + 1
3.从aaba扩展,可得b,aba,则sum + 2
4.从aaba扩展,可得a,则sum + 1
注意:每一位都算一个回文子串,没有去重的意思,请看上面的示例2
综上:sum = 5 ,但是,你会发现**这里面有个aaba是回文子串但是没有找出来
所以这里提出1位扩展是不行的,那么就2位扩展
根据上面的操作接下来续写2位扩展
5.从aaba扩展,可得aa,则sum + 1
6.后面aaba,aaba扩展就没有回文子串了
综上:sum = 6是正确答案
你会发现,继续增加扩展比如 aaba 3位扩展则与前面1位重复,4位扩展则与2位重复,所以,就只有1和2扩展两种情况
*到现在基本上就知道 回文子串的总数 = sum1 + sum2
暴力算法:
class Solution { public static int countSubstrings(String s) { int count = 0; //总计数 int size = s.length(); //字符串长度 for (int i = 0; i < size; i++){ for (int j = i + 1; j <= size; j++){ //这里j=i+1和j<=size是因为下面substring方法i取得到,j取不到 String s1 = s.substring(i, j); if (s1.equals(new StringBuffer(s1).reverse().toString())){ //判断是否是回文 count++; //计数+1 } } } return count; }
中心扩展算法:
class Solution { public static int countSubstrings(String s) { int sum = 0; for (int i = 0; i < s.length(); i++){ //遍历字符串 sum = sum + check(s, i, i) + check(s, i, i + 1); //1位和2位总和 } return sum; } public static int check(String s, int left, int right){ //传递参数作为左右指针,指的即所对应的字母 int count = 0; while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){ //由于是从中心扩展,所以从里到外,存在一个回文子串+1 left--; right++; count++; } return count; } }
3.进阶题—最长回文子串
说明:由于前面讲的是暴力算法和中心扩展算法,没有用动态规划来求解,故这里只讲前面两种方法求解,更容易理解接受
class Solution { int max = 0; String str = ""; public String longestPalindrome(String s) { //暴力 -- 超出时间限制 //求解方法就是 多设一个长度最大值max进行找出最大子串长度,相应的子串str则是最大的回文子串 // int max = 0; // String str = ""; //这里java需要初始化 // for (int i = 0; i < s.length(); i++){ // for (int j = i + 1; j <= s.length(); j++){ // String s1 = s.substring(i, j); // if (s1.equals(new StringBuffer(s1).reverse().toString()) && s1.length() > max){ //这里就是更改部分start // max = s1.length(); // str = s1; //end // } // } // } // return str; //中心扩展 for (int i = 0; i < s.length(); i++){ //更改部分start1 check(s, i, i); check(s, i, i+1); //end1 } return str; } public void check(String s, int left, int right){ while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){ String s1 = s.substring(left, right + 1); //更改部分start2 if (max < s1.length()){ max = s1.length(); str = s1; } //end2 left--; right++; } } }