解法一:暴力求解

一开始没想到什么好的思路,直接暴力求解,判断每一个子串。

  1. class Solution {
  2. public int countSubstrings(String s) {
  3. // 长度为1的都是
  4. int ans = s.length();
  5. for (int len = 2; len <= s.length(); ++len) {
  6. for (int i = 0; i <= s.length() - len; ++i) {
  7. if (judge(s.substring(i, i + len))) {
  8. ++ans;
  9. }
  10. }
  11. }
  12. return ans;
  13. }
  14. private boolean judge(String s) {
  15. int len = s.length();
  16. for (int i = 0; i < len / 2; ++i) {
  17. if (s.charAt(i) != (s.charAt(len - i - 1))) {
  18. return false;
  19. }
  20. }
  21. return true;
  22. }
  23. }

解法二:中心扩散法

回文串的中心要么为某个字符,要么介于相邻两个字符之间,共有N*2-1种选择。然后从中心分别向两边扩展,得出以以中心为中心的最长回文子串的长度。

  1. class Solution {
  2. public int countSubstrings(String s) {
  3. int ans = 0;
  4. for (int i = 0; i < 2 * s.length() - 1; ++i) {
  5. ans += move(s, i >> 1, (i + 1) >> 1);
  6. }
  7. return ans;
  8. }
  9. /**
  10. * 以两个指针的位置为起始向两边移动,求扩散过程中的回文子串数量
  11. *
  12. * @param s 源字符串
  13. * @param left 左侧起始点下标
  14. * @param right 右侧起始点下标
  15. * @return 扩散过程中的回文子串数量
  16. */
  17. private int move(String s, int left, int right) {
  18. int len = s.length();
  19. int ans = 0;
  20. while ((left >= 0) && (right < len)) {
  21. if (s.charAt(left) != s.charAt(right)) {
  22. break;
  23. }
  24. ++ans;
  25. --left;
  26. ++right;
  27. }
  28. return ans;
  29. }
  30. }

解法三:动态规划

DP[i][j]表示[i, j]这个区间的子串是否为回文串,则有如下DP方程。

647. 回文子串 - 图1

  1. class Solution {
  2. public int countSubstrings(String s) {
  3. int ans = 0;
  4. int n = s.length();
  5. boolean[][] flag = new boolean[n][n];
  6. int i, j;
  7. for (i = n - 1; i >= 0; --i) {
  8. for (j = n - 1; j >= i; --j) {
  9. if (i == j) {
  10. flag[i][j] = true;
  11. } else if (s.charAt(i) == s.charAt(j)) {
  12. if ((j - i) == 1) {
  13. flag[i][j] = true;
  14. } else {
  15. flag[i][j] = flag[i + 1][j - 1];
  16. }
  17. } else {
  18. flag[i][j] = false;
  19. }
  20. if (flag[i][j]) {
  21. ++ans;
  22. }
  23. }
  24. }
  25. return ans;
  26. }
  27. }

解法四:马拉车算法

马拉车算法参考:https://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html
官方题解:https://leetcode-cn.com/problems/palindromic-substrings/solution/hui-wen-zi-chuan-by-leetcode/

  1. class Solution {
  2. public int countSubstrings(String s) {
  3. int len = 2 * s.length() + 3;
  4. char[] chars = new char[len];
  5. chars[0] = '$';
  6. chars[len - 1] = '@';
  7. int index = 1;
  8. for (char ch:s.toCharArray()) {
  9. chars[index++] = '#';
  10. chars[index++] = ch;
  11. }
  12. chars[index] = '#';
  13. // 中心下标
  14. int center = 0;
  15. // 右边界下标(不包括)
  16. int right = 0;
  17. // 以下标i为中心的最长回文子串半径
  18. int[] Z = new int[len];
  19. for (int i = 1; i < len - 1; ++i) {
  20. if (i < right) {
  21. Z[i] = Math.min(Z[2 * center - i], right - i);
  22. }
  23. while (chars[i + Z[i] + 1] == chars[i - Z[i] - 1]) {
  24. ++Z[i];
  25. }
  26. if (i + Z[i] > right) {
  27. right = i + Z[i];
  28. center = i;
  29. }
  30. }
  31. int ans = 0;
  32. for (int i : Z) {
  33. ans += (i + 1) / 2;
  34. }
  35. return ans;
  36. }
  37. }