暴力法 中心拓展法 动态规划法 解决最长回文子串问题


LeetCode地址,以及本文主要参考了LeetCode的官方解答

比较简单的方法就是遍历所有的子串,然后判断这个子串是不是回文串.是的话就再判断长度,比已经搜索到的长,就记录下来.返回结果就好.一开始会觉得遍历的方法会怪怪的,但后来发现自己想多了.很好遍历.双层循环嵌套就好.第一层为开始字符的指针进行遍历,后面则遍历起始位置剩下的所有位置即可.

    public static String longestPalindrome(String s) {
        String res ="";
        int n = s.length();
        for(int i=0;i<n;i++){
            for(int j=i;j<=n;j++){
                if(j-i+1<=res.length())continue;
                String temp = s.substring(i,j);
                boolean flag = true;
                for(int k=0;k<temp.length()/2;k++){
                    if(temp.charAt(k)!=temp.charAt(temp.length()-1-k)){
                        flag = false;
                        break;
                    }
                }
                if(flag)res = temp;
            }
        }
        return res;
    }

算法的时间复杂度是O(n^3)

然后就是第一次真正实践的动态规划dp
其实说起来很简单,我不用公式进行说明.动态规划局就是找到一个递推公式,进行结果的判断.
比如这道题:我判断一个长度为五的字符串是不是回文,我只需要判断两头字母是否相等,以及去掉两头的字母是否还是回文.如果都是那就是回文.(推到最后就是一个字母,和两个字母的情况)所以我们从一个字母开始,到两个字母…整个字符串.这样就能算出所有子串是否为回文了.

public String longestPalindrome(String s) {
        String res ="";
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        for(int k=0;k<n;k++){
            for(int i=0;i+k<n;i++){
                int j = i + k;
                if(k == 0){
                    dp[i][j]=true;
                }
                else if(k==1){
                    dp[i][j]= s.charAt(i)==s.charAt(j);
                }
                else{
                    dp[i][j] = (s.charAt(i)==s.charAt(j)) && dp[i-1][j-1];
                }
                if(dp[i][j]&&k+1>res.length())res = s.substring(i,j+1);
            }
        }

        return res;
    }

时间复杂度是O(n^2)

然后是中心拓展法.其实我觉得也是暴力遍历法,不过遍历的方式比较巧妙.第一个方法遍历的字母是以那个字母为边界进行判断.而中心拓展法则是以字母作为中心进行遍历.我们遍历到一个字母以后,就向这个字母两边伸展开进行判断伸展以后的字符串是否是回文,如果是的话就继续伸展,不是的话就返回最长的伸展.因为后面也不可能是回文了(注意判断边界>=0,<=n)
然后还需要注意考虑的一点是,可能是一个字母为中心,可能是两个字母为中心,这个处理方法很巧妙,就是扩展的索引是都是从i开始和从i 和 i+1开始的区别.

 public  String longestPalindrome3(String s) {
        int start=0,end=0;
        int n = s.length();
        for(int i=0;i<n;i++){
            int len1 = expands(s,i,i);
            int len2 = expands(s,i,i+1);
            int len = Math.max(len1,len2);
            if(end-start+1<len){
                start = i - (len-1)/2;
                end = i + len/2;
            }

        }
        return s.substring(start,end+1);
    }
    public int expands(String s,int left,int right){
        int n = s.length();
        while (left>=0&&right<n&&s.charAt(left)==s.charAt(right)){
                left--;
                right++;
        }
        return right-left-1;
    }

复杂度是O(n^2)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rglkt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值