算法思路练习002-最长的回文子串

题目

给你一个字符串 s,找到 s 中最长的回文子串。

思路

  • s不为空并且长度小于2,直接返回
  • 暴力破解-没思路的时候就先暴力破解,再想办法优化
    通过双指针可以获取到所有的子串,然后拿到一个判断一个是否是满足回文条件。
  • 判断回文
    • 子串长度为偶数,left=len/2 - 1;right = len/2
    • 子串长度为奇数,left=right = len/2
    • 在子串长度范围内while(),判断s.charAt(left++)==s.charAt(right++)
      • 如果出现false,返回false。
      • 循环结束没有出现false,将s.len通过Math.max()存入待返回结果

代码尝试-有错

//最长回文子串
    @Test
    void longestPalindrome(){
        String s = "babad";
        int max = 0;
        String result = null;
        //获取所有子串
        for (int i = 0; i < s.length(); i++) {
            for (int j = i; j < s.length(); j++) {
                String subStr = s.substring(i, j);
                boolean isP = isPalindrome(subStr);
                if (isP) {
                    if (subStr.length() > max) {
                        result = subStr;
                        max = subStr.length();
                    }
                }
            }
        }
        System.out.println(result);
    }

    boolean isPalindrome(String s) {
        int left, right;
        int len = s.length();
        if (len % 2 == 0) {
            left = len / 2 - 1;
            right = len / 2;
        }else{
            left = right = len / 2;
        }
        while (left >= 0) {
            if (s.charAt(left) == s.charAt(right)) {
                left--;
                right++;
            } else return false;
        }
        return true;
    }

大致逻辑正常,但是返回有问题,关于subString()方法的问题

subString知识点

s.subString(int beginIndex,int endIndex)源码:
subString()源码
字符串生成的时候如果beginIndex和endIndex在同一个位置,不会生成beginIndex此位置字符的字符串,而是生成长度为0的"“。
所以在生成子串的内层for循环条件里,j不能从0开始,否则生成的第一个子串为”"。
要生成外层for循环里i位置的子字符串,那么j就一定要比i靠后一位。
jdk api 1.8:
在这里插入图片描述

解决

for (int j = i+1; j <= s.length(); j++) {

暴力破解几乎必定超时

在这里插入图片描述

第一大拦路虎——动态规划

遍历子字符串有两种方式:一种是固定边界,一种是固定子串长度。
我看leetcode官方解答用的是固定子串长度进行遍历
在这里插入图片描述
第一个for循环将子串长度固定,然后第二个for循环通过移动左边界进行移动子串的位置,就像一个固定大小的活动窗口在字符串上移动,圈出来一个一个的子字符串。

举例展示为什么动态规划可以节省时间?

以固定子串长度为例:
(当固定子字符串长度分别为len时,判断是否是回文需要判断的字符位置组合)
len2:0-1; 1-2; 2-3; 3-4; 4-5……
len3:0-2; 1-3; 2-4; 3-5; 4-6……
len4:0-3,1-2;1-4,2-3; 3-6,4-5; 4-7,5-6; ……
通过这三行举例,当子字符串长度为4时,比较过程中有一半都是在之前len=2时判断过的。
所以动态规划的核心就是开辟出一个空间(数组、list、map…),把之前判断过的结果存进去,后面可以拿到直接用,可以节省大量时间。
也就是用空间换时间

那么固定边界也可以使用空间换时间吗?

上面的暴力破解也属于固定边界的一种,固定左边界,移动右边界来遍历子字符串。尝试修改一下上面的暴力破解代码,核心思想就是new一个数组出来,把每次判断出来的比较短的回文字符串存进去,后面判断的时候先查数组,如果能查到就不需要再判断一次了。

{
            if(s.length() < 2){
                return s;
            }
            int max = 0;
            String result = null;
            //空间换时间的容器
            boolean[][] ap = new boolean[s.length()][s.length()];
			//所有一个字符的子串默认都满足回文判断
            for (int i = 0; i < s.length(); i++) {
                ap[i][i] = true;
            }
            int start = 0;
            int end = 0;
            //获取所有子串
            for (int i = 0; i < s.length(); i++) {
                for (int j = i+1; j < s.length(); j++) {
                    
                    boolean flag = true;

                    if (!ap[i][j]) {
                        int m = i;
                        int n = j;
                        while (m < n) {
                            if (s.charAt(m) == s.charAt(n)) {
                                m++;
                                n--;
                            } else {
                                flag = false;
                                break;
                            }
                        }

                        ap[i][j] = flag;

                        if (flag) {
                            if (j - i + 1 > max) {
                                max = j - i + 1;
                                start = i;
                                end = j;
                            }
                        }
                    }
                }
            }
            result = s.substring(start, end + 1);
            return result;

        }

对应一个初学者来说,算法真的是太不友好了😭😭😭
在这里插入图片描述

写的时候就能感觉到建了太多变量了……不知道是不是暴力破解逻辑的硬伤
去看标准答案去😭😭
不过也不要太气馁,初学阶段感觉算法拼的还是知识储备,就像能看懂答案但是不会自己做的数学题一样
继续加油

希望我永远都拥有开始的勇气。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值