(如果想查看最终代码,直接跳到最后,如果想看中间踩过的坑,可以看看过程)
题目如下:
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
Example 1:
Input: "A man, a plan, a canal: Panama"
Output: true
Example 2:
Input: "race a car"
Output: false
很容易想到用对撞指针,即给首尾各定义一个指针。碰到非数字和字母的元素,跳过,直到两个都是字母或者数字,进行比较。
错误一, 一开始忽略了数字(又是低级错误,没读懂数字字母的英文),所以提交后,0p(数字0,不是字母O)测试用例没通过。因为在我的代码里认为数字也是像符号一样可以忽略的。
后来改了判断范围,在本地以下代码通过
package collisionsPointer;
public class ValidPalindrome125 {
private static boolean isPalindrome (String s) {
char[] chars = s.toCharArray();
int l=0;
int r=chars.length-1;
while(l<=r) {
if(!((chars[l]>='0'&&chars[l]<='9')||(chars[l]>='a'&&chars[l]<='z')||(chars[l]>='A'&&chars[l]<='Z'))){
l++;
continue;
}
if(!((chars[r]>='0'&&chars[r]<='9')||(chars[r]>='a'&&chars[r]<='z')||(chars[r]>='A'&&chars[r]<='Z'))) {
r--;
continue;
}
//都是字母了
if(chars[l] != chars[r] && chars[l]+32 != chars[r] && chars[l]-32 != chars[r] ) {
return false;
}
else { //对应位置的字母相同,移动指针
l++;
r--;
}
}
return true;
}
public static void main(String[] args) {
String s1 = "0p";
boolean res = isPalindrome(s1);
System.out.println(res);
}
}
我为什么在自己的程序里没有直接取非法的范围,而是取到合法的范围然后取非,因为我假定此时并不知道各数字和字母ASCII码的范围(当然自己做题可以百度,假定此时不能百度),所以不好直接取非法的范围。
这个代码在本地{0p}能通过,但是提交到leetCode时,通不过.硬是将0P判断为ture,我也很无奈啊…
不过我发现了自己代码的另外一个bug :
判断两个字符是否相同或者为大小写的时候,直接用了比较两个字符的相等或者±32相等就认为是相同的,同样还是忽略的数字的问题,因为如果是大小写字母的话,这样判断没有问题,但是如果有数字,可能会出现数字的ASCII码+32与某一个字母的ASCII码一样,同样会判断错误。需要分开判断,所以虽然这个用例在本地侥幸判断正确的,但是代码其实是不完全正确的,
然后我就把代码改成了如下:
于是就出现了错误二:
char[] chars = s.toCharArray();
int l=0;
int r=chars.length-1;
while(l<r) {
if(!((chars[l]>='0'&&chars[l]<='9')||(chars[l]>='a'&&chars[l]<='z')||(chars[l]>='A'&&chars[l]<='Z'))){
l++;
continue;
}
if(!((chars[r]>='0'&&chars[r]<='9')||(chars[r]>='a'&&chars[r]<='z')||(chars[r]>='A'&&chars[r]<='Z'))) {
r--;
continue;
}
//都是字母数字了
//如果左边是数字,只比较大小
if((chars[l]>='0'&&chars[l]<='9')) {
if(chars[l] != chars[r]) {
return false;
}
}
//如果左边是字母
else {
//如果右边是数字,直接返回
if((chars[r]>='0'&&chars[r]<='9')) {
return false;
}
//如果右边也是字母,可判断大小写相等
else {
if(chars[l] != chars[r] && chars[l]+32 != chars[r] && chars[l]-32 != chars[r] ) {
return false;
}
else { //对应位置的字母相同,移动指针
l++;
r--;
}
}
}
}
return true;
提交结果:在{1b1}用例时:超时…这个…抓狂啊!
最后,用了java库自带的转换为小写库,这样就省去了复杂的判断过程,战战兢兢地提交:accpted.
Runtime: 3 ms, faster than 96.33% of Java online submissions for Valid Palindrome.
Memory Usage: 37.7 MB, less than 97.71% of Java online submissions for Valid Palindrome.
看百度有些人单独判断了空串或者只有一个字符的字符串,其实没必要,在while处都过不了,直接返回了true.
package collisionsPointer;
public class ValidPalindrome125 {
private static boolean isPalindrome (String s) {
s=s.toLowerCase();//就不存在大小写的问题了,直接比较是否相等
char[] chars = s.toCharArray();
int l=0;
int r=chars.length-1;
while(l<r) {
if(!((chars[l]>='0'&&chars[l]<='9')||(chars[l]>='a'&&chars[l]<='z')||(chars[l]>='A'&&chars[l]<='Z'))){
l++;
continue;
}
if(!((chars[r]>='0'&&chars[r]<='9')||(chars[r]>='a'&&chars[r]<='z')||(chars[r]>='A'&&chars[r]<='Z'))) {
r--;
continue;
}
if(chars[l] != chars[r]) {
return false;
}
else { //对应位置的字母相同,移动指针
l++;
r--;
}
}
return true;
}
public static void main(String[] args) {
String s1 = "p212P";
boolean res = isPalindrome(s1);
System.out.println(res);
}
}