leetcode 214. Shortest Palindrome(最短回文串)

题目描述

给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: “aacecaaa”
输出: “aaacecaaa”
示例 2:
输入: “abcd”
输出: “dcbabcd”

求解

什么是回文串?回文串就是指正着看和反过来看都是相同的字符串,即字符串对称。回文分为单回文和双回文,单回文字符串长度是奇数,这个字符串是以某个字符为中心对称的;双回文字符串长度是偶数,它并不以某个字符为中心。
初步分析:这题需要在前面补字符以达到对称,求最短回文串,最初我采用了选定某点然后向四周扩散补全的思路。具体实现的方法是把求解分为三个部分:求单回文奇数,单回文偶数,双回文,一般循环到字符串长度的一半就可以了,单回文在奇数和偶数下的截止位置不同,故分开讨论,最后总共需要三个循环。在循环中,两个指针从某点出发向两边运动,如果两个指针对应字符相等,则继续向两边运动,一旦low指针小于0,则开始把high指针对应的字符插入0位置,循环往复,知道high指针也运动到了字符串的最右侧。在不断获取回文串的过程中更新最短回文串并返回。
程序

class Solution {
	int length=10000000;
	String str="";
    public String shortestPalindrome(String s) {    	
    	if(s.length()%2==1){
	        for(int i=0;i<s.length()/2+1;i++){
	        	System.out.println(i);
	        	StringBuilder stringBuilder=get(s, i, i);
	        	if(stringBuilder!=null&&stringBuilder.length()<length){
	        		str=stringBuilder.toString();
	        		length=stringBuilder.length();
	        	}
	        }
    	}else{
    		for(int i=0;i<s.length()/2;i++){
    			System.out.println(i);
            	StringBuilder stringBuilder=get(s, i, i);
            	if(stringBuilder!=null&&stringBuilder.length()<length){
            		str=stringBuilder.toString();
            		length=stringBuilder.length();
            	}
    		}
    	}
        for(int j=0;j<s.length()/2;j++){
        	StringBuilder stringBuilder2=get(s,j,j+1);
        	if(stringBuilder2!=null&&stringBuilder2.length()<length){
        		str=stringBuilder2.toString();
        		length=stringBuilder2.length();
        	}
        }              
    	return str;
    }    
    public StringBuilder get(String s,int low,int high){
        StringBuilder sBuilder=new StringBuilder(s);
    	while(high<sBuilder.length()){
    		if(low>=0&&sBuilder.charAt(low)!=sBuilder.charAt(high)){
    			return null;
    		}else if(low>=0&&sBuilder.charAt(low)==sBuilder.charAt(high)){   			
    			low--;
    			high++;
    		}else if(low<0){
    			sBuilder.insert(0, sBuilder.charAt(high));

    			high+=2;
    		} 		
    	}
    	return sBuilder;
    }
    
}

结果:在最后一个“aaaa…aaaaaa”的测试案例中,时间超了,没有通过测试。代码时间复杂度太大,需要优化。回看代码,代码太过冗杂,用了3个循环!
重新整理思路:求解的最糟糕的情况是把字符串反转然后拼接在前面,比较好的情况是字符串的前面一部分存在对称,只要补充少数字符即可。因此,新的思路就是先把字符串反转得到一个反转字符串,然后在其中找到和原字符串中相同的部分。举个例子:
原字符串:acbca ab
反转:ba acbca
重叠部分:acbca
拼接:ba acbca +ab(反转串加上原字符串中的后两个字符)
重点就是反转后找相同的部分,然后拼接。
代码如下:

class Solution {
    public String shortestPalindrome(String s) {    	
    	if(s.length()<=1){
    		return s;
    	}else{
    		String string=new StringBuilder(s).reverse().toString();
    		for(int i=0;i<s.length();i++){
    			if(string.substring(i,string.length()).equals(s.substring(0, string.length()-i))){
    				return new StringBuilder(string).append(s.substring(s.length()-i,s.length())).toString();
    			}
    		}
    		return new StringBuilder(string).append(s).toString();    		
    	}    	
    }    
}

代码简洁了许多,只用到了一个for循环。代码也通过了Leecode的编译。
一个小细节:在字符串操作中,使用的是StringBuilder,它相比String和StringBuffer速度最快。String是存在在常量池中的,每次修改都要回收之前的垃圾并且在常量池中添加新的字符,很费时间;StringBuffer和StringBuilder基本的功能是一样的,但是StringBuffer因为是线程安全的,这限制了它的速度。所以在字符串操作中我们一般采用StringBuilder。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值