验证回文串
题目地址:https://leetcode-cn.com/problems/valid-palindrome/
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
**说明:**本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false
解法一:双指针
首先判断两个字符串是否是回文串,就是原串与倒序是否相等,那不就是前面写的反转字符串么。只不过就是首尾交换,换成首尾是否相等。但在此之前我们先要从原串中获取数字字母串并忽略大小写
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
| public boolean isPalindrome(String s) { if(s == null || s.length() == 0) return true; char[] arr = s.toCharArray(); int n = arr.length; StringBuilder cs = new StringBuilder(); for (int i = 0; i < n; i++) { char c = arr[i]; if (check(c)) { cs.append(change(c)); } } n = cs.length(); for(int i = 0; i < n/2; i++){ if(cs.charAt(i) != cs.charAt(n-i-1)){ return false; } } return true; }
public boolean check(char c){ return c>=48&&c<=57 || c>=65&&c<=90 || c>=97&&c<=122; }
public char change(char c){ return c>=65&&c<=90 ? c+=32 : 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 27 28 29 30
| public boolean isPalindrome(String s) { if(s == null || s.length() == 0) return true; char[] arr = s.toCharArray(); int n = arr.length; int start = 0; int end = n - 1; while(start < end){ while(start < end && !check(arr[start])){ start++; } while(start < end && !check(arr[end])){ end--; } if(change(arr[start])!=change(arr[end])){ return false; } start++; end--; } return true; }
public boolean check(char c){ return c>=48&&c<=57 || c>=65&&c<=90 || c>=97&&c<=122; }
public char change(char c){ return c>=65&&c<=90 ? c+=32 : c; }
|

解法三:栈
虽然这题双指针就是比较优的解法,但是前段时间学习了栈,因此在这题上用上温习一下不过空间和效率应该是最低的,我们都知道栈是后进先出(LIFO)一种数据结构。这里我们可以用数组实现一下栈完成一下基本的四个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Stack<E>{ List<E> arr = new ArrayList(); int top = -1; void push(E c){ arr.add(++top,c); } E pop(){ E c = peek(); arr.remove(top--); return c; } E peek(){ return arr.get(top); } boolean isEmpty(){ return top < 0; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public boolean isPalindrome(String s) { if(s == null || s.length() == 0) return true; char[] arr = s.toCharArray(); int n = arr.length; Stack<Character> stack = new Stack<>(); List<Character> list = new ArrayList<>(); for (int i = 0; i < n; i++) { char c = arr[i]; if (check(c)){ stack.push(change(c)); list.add(change(c)); } } int index = 0; while (!stack.isEmpty()){ if (stack.pop() != list.get(index++)) return false; } return true; }
|
总结
回文串处理的大体方式还是双指针、反转或者栈。对于此题Character类中提供了判断是否为数字或字母的方法和转大小写的方法。我上面是单独写的check(char c)与change(char c)方法。
1 2
| isLetterOrDigit(char c) toLowerCase(char c)
|
利用Java类库的话直接有反转方法当然它里面也是一次遍历处理,反转再比较。当然效率是比较低的可以参考
1 2 3
| String fz = cs.reverse().toString(); return cs.equals(fz);
|
总体来说呢可以实现的方式有很多,关注实现本身效率来说双指针是较优的。