描述
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 1:
输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".
示例 2:
输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".
注意:
输入的字符串长度不会超过1000。
解析
和[LeetCode] 5. 最长回文子串 ☆☆☆(最长子串、动态规划)类似,可以先考虑用中心扩展法,与其不同的是,记录回文子串个数。
也可以用动态规划。
思路为:
如果从i到j的字符串是回文字符串,那么如果i-1和j+1相等,那么从i-1到j+1就是回文字符串。
当然,如果是1个字符串,那么一定是回文的,如果是两个字符串,并且相等,那么也是回文的。
代码
中心扩展算法
public int countSubstrings(String s) { int count = 0; for (int i = 0; i < s.length(); i++) { count += count(s, i, i);//回文子串长度为奇数的情况 count += count(s, i, i + 1);//回文子串长度为偶数的情况 } return count; } public static int count(String s, int start, int end) { int count = 0; //start往左边跑,end往右边跑,注意边界 while (start >= 0 && end < s.length() && s.charAt(start--) == s.charAt(end++)) { count++; } return count; }
动态规划
public static int countSubstrings(String s) { int result = 0; boolean[][] dp = new boolean[s.length()][s.length()];//i到j位置的字符串是否为回文子串 for (int i = 0; i < s.length(); i++) { for (int j = 0; j <= i; j++) { if (i == j) { dp[i][j] = true;//i j相等,肯定是回文子串 } else {//i j不等的话,如果char一样,i j相差1,也符合;或者最近的内圈是回文子串 dp[i][j] = s.charAt(i) == s.charAt(j) && (j == i - 1 || dp[i - 1][j + 1]); } if (dp[i][j]) { result++; } } } // for (int i = s.length() - 1; i >= 0 ; i--) {//类似,只是从后往前 // for (int j = i; j < s.length(); j++) { // if (i == j) // dp[i][j] = true; // else // dp[i][j] = s.charAt(i) == s.charAt(j) && (j == i + 1 || dp[i + 1][j - 1]); // if (dp[i][j]) result++; // } // } return result; }