最长回文串之暴力法,中心扩展,动态规划

正读倒读都一样的整数 ,这个应该是最简单的介绍了吧。
用程序怎么简单实现呢?

示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

示例 2:
输入: “cbbd”
输出: “bb”

判断一个字符串是否是回文串

public class isPlalindrome {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入字符串:");
        String str = sc.nextLine();
        System.out.println(isPlalindrome(str));
    }
    public static boolean isPlalindrome(String str) {
        //将字符串转化为字符数组
        char[] array=str.toCharArray();
        int left=0,right=array.length-1;//记录数组的开始位置和结束位置
        while(left<right)//开始位置小于结束位置时,进行判断  两位置处于对称位置上
        {
            if(array[left++]!=array[right--])//如果两位值的字符不相同 则不对称
                return false;//返回false
        }
        //所有位除奇数位时的中间位均对应 返回true
        return true;
    }
}

这个程序应该不难理解

暴力法

 * 求解字符串的最长回文串----暴力法 O(n^3)
 * 通过两层循环找出字符串的所有子串  对每一个子串进行判断
 * 将是回文串的子串储存  当有新的回文串时,比较记录中的回文串和当前回文串的长度
 * 用较长的串替换当前串  如果两串长度相同,保留旧的
 * PS:如果想保存所有的回文串 可以修改记录回文串的结构为String数组(链表、hash表都可以)
public static String longestPlalindrome(String original)
    {
        //非空判断
        if((original==null)||original.length()==0)
        {
            return null;
        }
        //将字符串转换为字符数组
        char[] oriArray=original.toCharArray();
        int first=0;
        int end=0;//当前字符串中回文串的始末位置 包含末位置

        for(int i=0;i<oriArray.length-1;i++)//两次循环 查找字符串的所有子串
        {
            for(int j=i;j<oriArray.length;j++)
            {
                //判断子串是否为回文串
                int left=i,right=j;//记录左侧右侧的位置
                while(left<right)//左侧下标小于右侧下标时 比较未完成
                {
                    if(oriArray[left]!=oriArray[right])
                        break;//如果出现对称位置不相等元素  则不是回文串跳出循环
                    //判断下一对称位置
                    left++;
                    right--;

                }
                if(left>=right)//是否比较完成 是字符串是否为回文串的判断条件
                {
                    if(j-i>end-first)//查找到回文串 且长度大于当前存储的回文串长度
                    {
                        //替换当前回文串
                        first=i;
                        end=j;
                    }
                }
            }
        }
        //查找结束  将数组转化为字符串返回
        return String.valueOf(oriArray, first, end+1);
    }

动态规划

动态规划不是算法,是一种方法
为了改进暴力法,我们首先观察如何避免在验证回文时进行不必要的重复计算。考虑 “ababa” 这个示例。如果我们已经知道 “bab” 是回文,那么很明显, “ababa” 一定是回文,因为它的左首字母和右尾字母是相同的。

先看代码吧

 public static String longestPalindrome2(String s) {
    int len = s.length();
    if(len <= 1) return s;
    //字符串为空或者长度等于1,直接返回
    boolean[][] dp = new boolean[len][len];
    //记录每一个子串的状态,dp[i][j]=true表明,以i为起点,j为终点的子串是回文
    int max = 0;
    //最大回文长度
    String ret = s.substring(0, 1);
    //存放回文,初始化为s的第一个字符,假如该字符串没有回文,那就直接返回字符串的第一个字符
    for(int r = 1; r < len; r++){
        for(int l = 0; l <  r; l++){
            //这两个循环很关键,
            if(s.charAt(r) == s.charAt(l) && (r - l <= 2 || dp[l+1][r-1])){
                dp[l][r] = true;
                if(max < r - l + 1) {
                    max = r - l + 1;
                    //max值更新
                    ret = new String(s.substring(l, r + 1));
                    //存放新的回文
                }
            }
        }
    }
    return ret;
}

看懂了吗?一维数组?二维数组?如果要计算的字符串放到二位数组里面,你会惊奇的发现?s[a,b]是回文的话,是s[a]=s[b],轴对称的。

中心扩展算法

事实上,只需使用恒定的空间,我们就可以在 O(n^2)的时间内解决这个问题。我们观察到回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n - 12n−1 个这样的中心。

public static String longestPalindrome(String s) {
        if (s == null || s.length() < 1)
        {
            return "";
        }
        int start = 0, end = 0;
        //子串在原字符串中的定位
        for (int i = 0; i < s.length(); i++) {
            int len1 = expandAroundCenter(s, i, i);
            //判断奇数个 abcba
            int len2 = expandAroundCenter(s, i, i + 1);
            //判断偶数个 abba
            int len = Math.max(len1, len2);
            //比较两个谁更长
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
            //以上是不懂意思
        }
        return s.substring(start, end + 1);
    }
    /*
     * @Author liuhaidong
     * @Description 中心结点法
     * @Date 9:50 2019/9/16 0016
     **/
    private static int expandAroundCenter(String s, int left, int right) {
        int L = left, R = right;
        while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
            L--;
            R++;
        }
        return R - L - 1;
    }

就是那中间数,然后两边比较

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值