每天一道算法题(三)找出最长的回文子字符串

Problem:Finding the longest palindromic substring.
palindromic substring即正读和反读都一样的字符串


思路一(代码在下面):

  1. 列表内容遍历字符串,把字符串中的每个非连续重复字符当做中心字符 c
    (如果存在连续重复的字符,把这几个字符作为中心字符串 c, 如:”abccccd”中的”cccc”)
  2. 比较这个中心字符或字符串的左一字符left和右一字符right为否一致
  3. 如果一致,比较左二字符与右二字符直到l和r不一致

O(n)的时间复杂度
O(n)的空间复杂度(递归)


在吃午饭的时候在思考第一种方法,但当时被取出重复的字符难住了,当时突然觉得用stack应该会很简单,之后又写了第二种栈方法

思路二:

  1. 选出中间的字符或中间字符串
  2. 建一个stack,存入字符串的起始到中间字符
  3. IF 中间字符和之后几个字符连续重复,
    则把这几个重复的字符扩展到子字符串
    ELSE 则只把它扩展到子字符串
  4. 把中间字符出栈
  5. 比较中间字符的下一个非重复字符与stack.pop()比较
    IF 相等
    把stack.pop()扩展到子字符串的首和尾
    ELSE 输出结果

    O(n*n)的时间复杂度


其他人的方法(方法都在此地址):

(三)Naive Approach
we can simply examine every substring and check if it is palindromic. The time complexity is O(n^3).
(四)Dynamic Programming
动态规划算法wiki
动态规划常常适用于有重叠子问题[1]和最优子结构性质的问题,动态规划方法所耗时间往往远少于朴素解法。
思路:
* 1.dp[i][j]表示从i到j的字符串是否是回文串
* 回文赋true,否则赋false
* i = j,单个字符,回文
* i > j,空串,回文
* 2.令k = j - i为动态算法中的状态增量
* 把dp[i][j]的1.中已知结果记录到二维数组中
* dp[i][j]的结果取决于dp[i + 1][j - 1]的结果
* 且如果dp[i][j] = true,则此字符串长度 k + 1
关于动态规划算法的经典问题请看01背包问题的java实现
(五)A Simple Algorithm
此方法与我上面写的方法一类似,但是更加合理以及简洁。
区别:
1.在方法伊始就进行了字符串的空串以及只有一个字符的字符串的判定
2.把方法一中的连续重复字符判定方法结合在了isLeftEqlRight方法里,并且此方法也更加简洁。
3.Time O(n^2), Space O(1)


代码

思路一:

    String str = "abbaddabbabcccba";
    char[] cha = str.toCharArray();
    // 连续重复字符的最左边字符
    int left = 0;
    // 连续重复字符的最右边字符
    int right = 0;

    @Test
    public void findLongest(){
        String destStr= cha[0] + "";
        for (int i = 0; i < cha.length; i++) {
            left = i;
            right = isCenterStr(i);
            destStr = isLeftEqlRight(right, left, destStr);
        }
        System.out.println(destStr);
    }
    /**
     * 比较这个中心字符或字符串的左一字符left和右一字符right为否一致
     * 一致左二和右二继续比较直至不一样
     */
    private String isLeftEqlRight(int right, int left,String destStr) {
        System.out.println();
        if (left > 0 && right < str.length() - 1&&(cha[left - 1] == cha[right + 1] )) {
                left--;
                right++;
                return isLeftEqlRight(right, left,destStr);
        }else {
                if (right - left > destStr.length()) {
                    StringBuilder dest = new StringBuilder();
                    dest.append(str,left,right + 1);
                    destStr = dest.toString();
                }
        }
        return destStr;
    }
    /**
     * 判断是否有连续重复字符
     * if yes
     * return 此连续字符的最后一个字符的位置   
     */
    public int isCenterStr(int i){

        if (i == cha.length - 1 || cha[i] != cha[i + 1]) {
            return i;
        }
        if (cha[i] == cha[i + 1]) {
            i++;
            right = isCenterStr(i);
        }
        return right;
    }

output:  
    abbaddabba

思路二(stack方式):

    String str = "abbaddabbabcccbada";
    char[] cha = str.toCharArray();

    @Test
    public void findLongest(){

        String subStr = cha[0] +"";
        /**
         * i为中间字符
         */
        for (int i = 4; i < cha.length;i++) {
            int j = i;
            Stack<Character> stack = new Stack<Character>();
            StringBuilder deStr = new StringBuilder();

            for (int k = 0; k <= i; k++) {
                stack.push(cha[k]);
            }
            if (j == cha.length - 1) {
                continue;
            }

            while (stack.peek().equals(cha[j + 1])) {
                boolean flag = true;
                if (flag) {
                    deStr.append(stack.peek());
                    flag = false;
                }
                deStr.append(cha[j + 1]);
                if (j < cha.length - 1) {
                    j++;
                }else{
                    break;
                }
            }
            stack.pop();

            while (stack.peek().equals(cha[j + 1])) {
                deStr.append(stack.peek());
                deStr.insert(0,stack.peek());
                stack.pop();
                if (j < cha.length - 2&&!stack.isEmpty()) {
                    j++;
                }else{
                    break;
                }
            }
            if (deStr.length() > subStr.length()) {
                subStr = deStr.toString();
            }
        }
        System.out.println(subStr);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值