力扣中等难度第5题 最长回文子串 一直提示“超出时间限制”解决方案

先看一眼题:
在这里插入图片描述

我的思路:正反向计算哈希,相同则说明是回文串,相比直接两两字符进行比较,减少了比较的次数。如果 maxLen已经比剩余子串的总长度还长,则可以跳出循环。
需要注意:计算哈希的时候,不要超过long的值。
我定义的哈希函数为:s.charAt(i)*26^k,其中k=0,1,2,3,4.当k为5时,令其等于0,避免太大。
通过哈希来判断一个字符串是不是回文串:

public static boolean hashCalculation(String s) {
        long forward = 0, reverse = 0;
        //奇数则算[0,len/2]和[len/2,len),偶数则算[0,len/2)和[len/2,len)
        int len = s.length();
        int i = 0, j = len - 1;
        int k = 0;
        for (; i < len / 2; i++,k++) {
            forward += Math.pow(26, k) * s.charAt(i);
//            if (forward > Math.pow(2, 16))
//                forward = (long) (forward / Math.pow(20, i));
            if(k%5==0)
                k=0;
        }
        if (len % 2 != 0) {
            //len为奇数奇数
            forward += Math.pow(26, k) * s.charAt(i);
        }
        for (k = 0; j > len / 2 - 1; j--, k++) {
            reverse += Math.pow(26, k) * s.charAt(j);
//            if (reverse > Math.pow(2, 16))
//                reverse = (long) (reverse / Math.pow(20, i));
            if(k%5==0)
                k=0;
        }
        return forward == reverse;
    }

然后在此基础上,寻找最长的回文子串

public static String longestPalindrome(String s) {
        if (s.length() == 0)
            return "";
        if (s.length() == 1)
            return s;
        int i = 1, j = 0;
        String sub = s.substring(0, 1);//如果最后没有回文串,那就返回第一个字符,因为第一个字符本身也是回文串
        int maxLen = 0;
        while (j < s.length()) {
            for (; i < s.length(); i++) {
                if (s.charAt(j) == s.charAt(i))
                    break;
            }
            if (i < s.length() && hashCalculation(s.substring(j, i + 1))) {
                // 如果新的回文子串比原来的大,才更新
                if (s.substring(j, i + 1).length() > maxLen) {
                    sub = s.substring(j, i + 1);
                    maxLen = sub.length();
                }
            }
            i++;
            if (i - 1 == s.length()) {
                j++;
                if (maxLen > s.length() / 2)
                    break;
                i = j + 1;
            }
        }
        return sub;
    }

提交!结果显示“超出时间限制”
明明我在自己电脑上跑是没有问题的呀!那么只有一种原因,就是时间复杂度过高了!计算量太大了!
因此在此基础上,加了一个栈:
·思路二: 思路一在我的电脑上可以跑通,但是在Leetcode上会超时,比如测试一千个"a"组成的字符串,比较的次数太多了!因此要进行优化
·优化思路:比较最大的串,如果不是回文串再比较子串,比如测试abcbaea,先比较abcbaea,再比较abcba。
·优化原理:如果大串是回文串,则不考虑其内部的子串
·写的时候发现这样做还可以避免很多i的边界比较问题,进一步提高了效率

修改后的代码如下:

public static boolean hashCalculation(String s) {
        long forward = 0, reverse = 0;
        //奇数则算[0,len/2]和[len/2,len),偶数则算[0,len/2)和[len/2,len)
        int len = s.length();
        int i = 0, j = len - 1;
        int k = 0;
        for (; i < len / 2; i++,k++) {
            forward += Math.pow(26, k) * s.charAt(i);
            if(k%5==0)
                k=0;
        }
        if (len % 2 != 0) {
            //len为奇数奇数
            forward += Math.pow(26, k) * s.charAt(i);
        }
        for (k = 0; j > len / 2 - 1; j--, k++) {
            reverse += Math.pow(26, k) * s.charAt(j);
            if(k%5==0)
                k=0;
        }
        return forward == reverse;
    }

public static String longestPalindrome(String s) {
        if (s.length() == 0)
            return "";
        if (s.length() == 1)
            return s;
        int i = 1, j = 0;
        String sub = s.substring(0, 1);//如果最后没有回文串,那就返回第一个字符,因为第一个字符本身也是回文串
        int maxLen = 0;
        Stack stack = new Stack();
        while (j < s.length()) {
            for (; i < s.length(); i++) {
                if (s.charAt(j) == s.charAt(i))
                    stack.add(i);
            }
            while (!stack.isEmpty()){
                int index = (int)stack.pop();
                if (hashCalculation(s.substring(j, index + 1)) && s.substring(j, index + 1).length() > maxLen) {
                    sub = s.substring(j, index + 1);
                    maxLen = sub.length();
                    break;
                }
            }
            stack.clear();
            j++;
            i=j+1;
            // 如果 maxLen已经比剩余子串的总长度还长,则可以跳出循环
            if(maxLen>s.substring(j,s.length()).length())
                break;
        }

        return sub;
    }

提交!还是超出时间限制!!
其实这样改动过后时间复杂度并没有任何变化,只是对于一些特殊的情况而言,变得比原来快一点了。
看来我是聪明反被聪明误了,直接暴力解法进行比较,其实是比计算哈希要快的,本来已经毫无思路了,就试了一下暴力解法,代码如下:

// 事实证明直接比较会比计算哈希要快
    public static boolean isPalindrome(String s){
        for(int i = 0 , j = s.length()-1 ; i<s.length()/2 ; i++,j--)
            if(s.charAt(i)!=s.charAt(j))
                return false;
        return true;
    }

只需要把上面的主程序中的hashCalculation替换为isPalindrome即可运行。
再次提交,成功了!但是速度慢的一批,因为暴力解法是最慢的解法了(我上面俩更慢,hhh)看了一眼答案,用的dp,头有点大,dp的思路明白了,但是dp怎么写成代码,看了一眼还是没懂,今天懒得看了,这里也就不粘贴答案代码了,有兴趣的小伙伴直接上leetcode官网上看吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值