leetcode hard模式专杀214. Shortest Palindrome

题干: https://leetcode.com/problems/shortest-palindrome/

 

虽说是hard模式,这题还真没给我什么hard的感觉。这种回文的问题,多在纸上画画比较利于分析,尤其是通过一种近乎几何直觉的方式会更有帮助。

比如给一个字符串aacecaaa,让你左边添加一些字符,变成回文,啥叫回文?就是轴对称嘛,那么就意味着这个补齐后的字符串如果是奇数长度,必然有一个字符是对称轴,如果是偶数长度,必然有一个字符与字符之间的槽(或者叫缝隙吧)是对称轴。

但是到底补齐之后的串是偶数还是奇数呢?不知道,于是最好分类讨论一下,把两种情况的解都找出来,然后取短者即可。

我就以奇数长度为例子做个说明,偶数长度的思想也不过大同小异。

明确一个目标,就是找对称轴位置,只要找到了对称轴,那么剩下的不过是一些简单的补齐操作而已。

那么对称轴位置需要满足什么条件呢?

假设某个index的字符为对称轴,那么可以想象,这个对称轴的位置必然在整个现有字符串(即还没有添加前缀的原始字符串)的左半部分(包括正中)位置,这样我们才能在左边补字符时补到对称,当然最好的case是我们啥也不补就已经对称,那么这个对称轴位置必然在原始字符串的正中间字符串。说上面这一点只是给对称轴定了个粗略的范围,然后我们要尽量在这个范围内找靠右的位置做对称轴。因为对称轴越靠右,左边就越能少补字符串。接下来就是评估哪些位置可以做对称轴,哪些不能做了。

也容易想到,如果某个index左右等距的两个字符已经出现了不等,那么这个index就不可能是对称轴,根据这个原则,我们就可以排除不合法的对称轴候选项。最终得出可能的最靠右的对称轴位置。找到后,将对称轴右侧的子串进行翻转,再跟对称轴以及其右边子串整体拼接成一个回文返回。

偶数串的思路大同小异,这里就不再赘述,下面看代码:

package com.example.demo.leetcode;

public class ShortestPalindrome {
    public String shortestPalindrome(String s) {
        if(s.length()<1){
            return s;
        }
        String jishuShortest = jishu(s);
        String oushuShortest = oushu(s);

        if(jishuShortest.length()<oushuShortest.length()){
            return jishuShortest;
        }else{
            return oushuShortest;
        }
    }

    private String oushu(String s){
        //以rightMostPossibleBeforeIndex为下标的元素的前面的slot为对称轴
        int rightMostPossibleBeforeIndex = (s.length()-1)/2;
        int correctBeforeIndex = rightMostPossibleBeforeIndex;
        for(int i=rightMostPossibleBeforeIndex;i>=0;i--){
            boolean slotDuichen = checkSlotDuichen(s, i);
            if(slotDuichen){
                correctBeforeIndex = i;
                break;
            }
        }
        return doOushuPrefix(s, correctBeforeIndex);
    }

    private String jishu(String s){
        int rightMostPossibleIndex = (s.length()-1)/2;

        int duichenIndex = 0;
        for(int i=rightMostPossibleIndex;i>=0;i--){
            boolean duichen = checkDuichen(s, i);
            if(duichen){
                duichenIndex = i;
                break;
            }
        }

        return doPrefix(s, duichenIndex);
    }

    String reverseString(String s){
        return new StringBuilder(s).reverse().toString();
    }

    private String doPrefix(String s, int duichenIndex){
        String rightPart = s.substring(duichenIndex);
        String leftPart = reverseString(s.substring(duichenIndex+1));
        return leftPart+rightPart;
    }

    private String doOushuPrefix(String s, int slotIndex){
        String rightPart = s.substring(slotIndex);
        String leftPart = reverseString(rightPart);
        return leftPart+rightPart;
    }

    private boolean checkDuichen(String s, int midIndex){
        if(midIndex==0){
            return true;
        }
        for(int j=midIndex-1;j>=0;j--){
            if(s.charAt(j)!=s.charAt(2*midIndex-j)){
                return false;
            }
        }
        return true;
    }

    private boolean checkSlotDuichen(String s, int slotIndex){
        if(slotIndex==0){
            return true;
        }
        for(int j=slotIndex-1;j>=0;j--){
            if(s.charAt(j)!=s.charAt(2*slotIndex-j-1)){
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) {
        String orgin = "";
        ShortestPalindrome demo = new ShortestPalindrome();
        String ret = demo.shortestPalindrome(orgin);
        System.out.println(ret);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值