leetcode 最长回文子串

182 阅读2分钟

回文的意思是正着念和倒着念一样,如:上海自来水来自海上

  • 思路:(注:「天然」的回文,指的就是后面的字符与当前字符一样的情况;比如:aaa、bbbb,这就是「天然」的回文)
  1. 我们有一个字符串或者字符数组,遍历到每一个下标 idx,先去找这个下标后面有没有跟当前值一样的,因为后面值都一样的话,「天然」地就形成了回文;然后把这一串字符串的首位两个指针当做判断回文的起点;我们称这两个指针为 low & high;

  2. 不过,不管是真的形成「天然」的回文,比如:bbb;还是没有形成「天然」的回文,只是一个单独的字符,比如:b;我们都要正常去定义 low & high;

  3. 如果 low-- 和 high++ 对应的值相等,就形成了回文;

  4. 不相等退出循环,遍历下一个下标,继续循环...

  • 例子:
  1. 比如:arr="acbbbbca"

  2. 我现在遍历到下标 idx=2,得到值:b 去判断后面一直到下标到 5 得到的值都是一样的,然后我把这一串值:bbbb 的 low=2 & high=5 当做我去判断回文的两个起点;

  3. 然后分别 low-- 和 high++ ;他们对应的值分别为 c 和 c,形成回文,那么就继续...

  4. 没有形成回文,就退出,我们继续增加下标 idx,继续遍历字符数组

  •   /**
       * 回文的意思是正着念和倒着念一样,如:上海自来水来自海上
       */
      public class Test {
      
          public static void main(String[] args) {
              Test test = new Test();
              System.out.printf("结果:%s\n", test.longestPalindrome("acccacbbbcab"));
          }
      
          public String longestPalindrome(String s) {
              int[] result = new int[2]; //result 保存结果
              char[] str = s.toCharArray();
              for (int i = 0; i < s.length(); i++) {
                  i = findLongest(str, i, result);
              }
              return s.substring(result[0], result[1] + 1);
          }
      
          /**
           * 注:「天然」的回文,指的就是后面的字符与当前字符一样的情况;比如:aaa、bbbb,这就是「天然」的回文
           * 遍历到每一个下标 idx,先去找这个下标后面有没有跟当前值一样的,因为你后面值都一样,「天然」地就形成了回文;然后把这一串字符串的首位两个指针当做判断回文的起点;
           * 比如:arr={acbbbbca}
           * 我现在遍历到下标 idx=2,我先去判断值:b 后面一直到下标=5,他们是值一样的,然后我把这一串值:bbbb 的low=2;high=5 当做我去判断回文的两个起点,
           * 然后分别 low-- 和 high++ ;他们对应的值分别为 c 和 c,形成回文,那么就继续...
           * 总结:
           * 用当前的下标往后遍历得到属于重复字符这种「天然」的回文,不管是真的形成「天然」的回文,比如:bbb;还是没有形成「天然」的回文,只是一个单独的字符,比如:b
           * 都要去定义这个「天然」回文的两个指针,low & high,如果 low-- 和 high++ 对应的值相等,就形成了回文
           * Q:那为什么这个方法需要返回 i 呢;
           * A:其实不返回这个 i 也不影响结果,返回 i 确实能少一定次数的遍历,但是我确实没看明白具体原因
           */
          public static int findLongest(char[] str, int low, int[] result) {
              int high = low;
              //先去查找是否有「天然」的回文,这个「天然」回文的字符串的首位两个指针,是我们 low-- & high++ 的第一步;不过,就算没有
              while (high < str.length - 1) {
                  char c = str[low];
                  char c1 = str[high + 1];
                  if (c == c1) {
                      high++;
                      System.out.printf("进入特殊处理的场景,因为 low 对应的值:%s 与 high+1 对应的值:%s 一样,high++,得到:%s\n", c, c1, high);
                  } else {
                      break;
                  }
              }
              StringBuilder temp = new StringBuilder();
              for (int i = low; i <= high; i++) {
                  temp.append(str[i]);
              }
              System.out.printf("当前遍历到下标:%s,「天然」的回文串是:%s,low:%s;high:%s\n", low, temp.toString(), low, high);
              int ans = high;//定位中间部分的最后一个字符
              while (low > 0 && high < str.length - 1) {//从中间向左右扩散
                  char lowc = str[low - 1];
                  char highc = str[high + 1];
                  System.out.printf("low - 1:%s;high + 1:%s\n", lowc, highc);
                  if (lowc == highc) {
                      System.out.print("low - 1 与 high + 1 形成回文,那就 low-- high++ 再试验下能否形成回文\n");
                      low--;
                      high++;
                  } else {
                      System.out.print("low - 1 与 high + 1 没有形成回文,退出\n");
                      break;
                  }
              }
              if (high - low > result[1] - result[0]) {
                  System.out.printf("新生成范围更大,新下标-high:%s,新下标-low:%s;老下标-high:%s,老下标-low:%s\n", high, low, result[1], result[0]);
                  result[0] = low;
                  result[1] = high;
              }
              System.out.printf("返回的新起点:%s\n", ans);
              return ans;
          }
      
      }