题目
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
思路1
只考虑数字和字母,所以要对字符串进行一些清洗,然后,利用StringBuffer里面的反正字符串,将前后结果一比较,就可以得出结论了。
代码
package leetcoder;
//本题只考虑数字和字母(字母忽略大小写)
class Solution {
public boolean isPalindrome(String s) {
if (s.length()==0)
return true;
else
{
s=s.toLowerCase();//先将s中的大写字母转为小写字母
String test = "";
char c;
for (int i=0;i<s.length();++i)
{
c=s.charAt(i);
if ((c>='0'&& c<='9')||(c>='a'&&c<='z'))
test+=c;//清洗,找出数字和字母
}
StringBuffer a=new StringBuffer(test);
String result=a.reverse().toString();
if (result.equals(test))
return true;
return false;
}
}
}
结果
虽然A是A了,但是这算法是真的烂,完全没有技术含量的。首先,数据要转化成为大小写,那个地方耗时O(n),然后,再进行数据清洗,又耗时O(n),完全没有技术含量,只是利用java自带的方法而已。
思路2
利用双指针来进行判断,在最前面和最后面分别设置一个指针,不断往中间靠拢,如果两个字符不相等则返回false,否则为true
代码
class Solution {
public boolean isPalindrome(String s) {
//数据清洗
s=s.toLowerCase();
String test="";
for (int i=0;i<s.length();++i)
if (Character.isLetterOrDigit(s.charAt(i)))
test+=s.charAt(i);
//长度为0,或者为1都是直接返回true,防止下面的下标越界
if (test.length()==0||test.length()==1)
return true;
int left=0;
int right=test.length()-1;
while (right>left)
{
if (test.charAt(left)!=test.charAt(right))
return false;
else
{
++left;
--right;
}
}
return true;
}
}
结果
我还以为有点改进的,想不到还是这么烂。不过也是,光数据清洗的转小写和找字符,都跟上个算法一样了。甚至下面花费的时间更多,烂。。。
官方双指针
代码:
class Solution {
public boolean isPalindrome(String s) {
StringBuffer sgood = new StringBuffer();
//这波长度处理得很细节,不用每次都计算一次,节省时间,典型利用空间换时间
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (Character.isLetterOrDigit(ch)) {
//添加的时候,顺便转成字符串,比我上面那个算法好的地方,就是不用遍历两遍,挺好的,学起来
sgood.append(Character.toLowerCase(ch));
}
}
int n = sgood.length();
int left = 0, right = n - 1;
while (left < right) {
if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))) {
return false;
}
++left;
--right;
}
return true;
}
}
官方结果
看了官方之后再改进
看了官方题解之后,我再改进我的代码,在添加的时候顺便转小写了,然后,把判断长度为1或者为0的那个顺便去了,因为长度为1或者0,那个right>left不会进入,所以直接返回true。不用浪费时间
class Solution {
public boolean isPalindrome(String s) {
//数据清洗
String test="";
for (int i=0;i<s.length();++i)
if (Character.isLetterOrDigit(s.charAt(i)))
//学习官方的,再添加的时候,顺便转小写
test+=Character.toLowerCase(s.charAt(i));
int left=0;
int right=test.length()-1;
while (right>left)
{
if (test.charAt(left)!=test.charAt(right))
return false;
else
{
++left;
--right;
}
}
return true;
}
}
结果
结果还是这个样子。这个时候,我就意识到事情不简单。肯定是我哪里有问题了?结果一想,还真是。官方利用StringBuffer来存储代码,它是一个可变长度的字符串对象,而我用的String是一个不可变长度的字符串。所以,每次官方代码只是在后面新增一个新的字符,而我确实重新创建一个新的字符串,怪不得这么慢。
String,StringBuffer和StringBuder的联系与区别
再再次改进的代码
class Solution {
public boolean isPalindrome(String s) {
//数据清洗
StringBuffer test=new StringBuffer();
for (int i=0;i<s.length();++i)
if (Character.isLetterOrDigit(s.charAt(i)))
//学习官方的,再添加的时候,顺便转小写
test.append(Character.toLowerCase(s.charAt(i)));
/* if (test.length()==0||test.length()==1)
return true;*/
int left=0;
int right=test.length()-1;
while (right>left)
{
if (test.charAt(left)!=test.charAt(right))
return false;
else
{
++left;
--right;
}
}
return true;
}
}
结果
这个就证明了我上面的想法是对的,所以,数据结构真的很重要呀。一种数据的组织形式不同,结果使用时间相差了60多倍。总算有点收获,还不错。。。