leetcode#125 Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

For example,
"A man, a plan, a canal: Panama" is a palindrome.
"race a car" is not a palindrome.

Note:
Have you consider that the string might be empty? This is a good question to ask during an interview.

For the purpose of this problem, we define empty string as valid palindrome.

解释:

给定一个字符串,判断该字符串是否是回文字符串,只考虑字母和数字,不考虑大小写。

例如:

A man, a plan, a canal: Panama 是一个回文字符串。
race a car 不是一个回文字符串。

注意:

怎么考虑一个空字符串?(这是一个好问题)

这里就定义,空字符串也是一个回文字符串。

理解:

本题是判断一整个字符串是否有回文,所以可以用两个指针,分别指向字符串的起始与结束的位置,然后由两端逐渐往中部移动,并在移动的过程中进行字符的比较。

由于本题只考虑字母和数字,同时不考虑字母的大小写,因此在判断字符ASCII码范围之外,还需要在遇到字母的时候,变换大小写以便判断是否是同一个字母。

我的解法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Solution {
public boolean isPalindrome(String s){
if(s.length() == 0) { return true; }
int head = 0;
int tail = 0;
char charFront = ' ';
char charBack = '.';
for(int i = 0;i < s.length() - 1;i++) {
tail++;
}
while(head < tail) {
boolean flagFront = true;
boolean flagBack = true;
// 字母和数字的ASCII码:0~9(48-57) A~Z(65-90) a~z(97-122)
while(flagFront) {
if((s.charAt(head) >=48 && s.charAt(head) <= 57) || (s.charAt(head) >= 65 && s.charAt(head) <= 90) || (s.charAt(head) >= 97 && s.charAt(head) <= 122)) {
charFront = s.charAt(head);
flagFront = false;
}
else{
head++;
if(head >= s.length()) { return true; }
}
}
while(flagBack) {
if((s.charAt(tail) >=48 && s.charAt(tail) <= 57) || (s.charAt(tail) >= 65 && s.charAt(tail) <= 90) || (s.charAt(tail) >= 97 && s.charAt(tail) <= 122)) {
charBack = s.charAt(tail);
flagBack = false;
}
else{ tail--; }
}
if(charFront == charBack) {
tail--;
head++;
}
else if((charFront - 48 >= 0 && charFront - 48 <= 9) || (charBack - 48 >= 0 && charBack - 48 <= 9)) {
return false;
}
else if(charFront - 32 == charBack || charBack - 32 == charFront) {
tail--;
head++;
}
else{
return false;
}
}
return true;
}
}
大神解法:

解法一:

非常的简洁,用到了很多String的方法:

  • String.replaceAll(String regex, String r),利用字符串 r 替换原字符串中符合正则表达式 regex 的字符串部分;
  • String.toLowerCase(),将字符串中的字母全部转换成小写的形式;
  • StringBuffer(String s),由于字符串是常量,所以想要生成原字符串的逆序字符串,必须新创建一个字符串,可以使用StringBuffer(速度较慢,但是线程安全),也可以使用StringBuilder(速度较快,但是非线程安全);
  • StringBuffer.reverse(),还处于StringBuffer阶段时,还不是字符串常量,所以此时还是可以对其进行逆序操作的;
  • StringBuffer.toString(),将StringBuffer对象转换为字符串常量。

由于用到了很多库方法,其速度自然会很慢。

1
2
3
4
5
6
7
public class Solution {
public boolean isPalindrome(String s) {
String actual = s.replaceAll("[^A-Za-z0-9]", "").toLowerCase();
String rev = new StringBuffer(actual).reverse().toString();
return actual.equals(rev);
}
}

解法二:

本解法的思想与我得解法的思想一致,但是它在判断数字和字母的时候,采用了JAVA库方法——Character.isLetterOrDigit(char c),看起来会整洁许多,但是势必会造成程序运行速度的下降。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Solution {
public boolean isPalindrome(String s) {
if (s.isEmpty()) {
return true;
}
int head = 0, tail = s.length() - 1;
char cHead, cTail;
while(head <= tail) {
cHead = s.charAt(head);
cTail = s.charAt(tail);
if (!Character.isLetterOrDigit(cHead)) {
head++;
} else if(!Character.isLetterOrDigit(cTail)) {
tail--;
} else {
if (Character.toLowerCase(cHead) != Character.toLowerCase(cTail)) {
return false;
}
head++;
tail--;
}
}
return true;
}
}

总结:

JAVA库方法固然给程序的编写带来了方便,缩短了开发周期,但是在考虑性能和运行速度的时候,往往还是需要注意一下库方法的使用频率,时间允许的情况下,可以考虑造一个性能更优、更适合当前场景的“轮子”。