题目地址:https://leetcode-cn.com/problems/valid-palindrome/java
给定一个字符串,验证它是不是回文串,只考虑字母和数字字符,能够忽略字母的大小写。git
说明:本题中,咱们将空字符串定义为有效的回文串。数组
示例 1:数据结构
输入: "A man, a plan, a canal: Panama"
输出: trueapp
示例 2:学习
输入: "race a car"
输出: false优化
首先判断两个字符串是不是回文串,就是原串与倒序是否相等,那不就是前面写的反转字符串么。只不过就是首尾交换,换成首尾是否相等。但在此以前咱们先要从原串中获取数字字母串并忽略大小写ui
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; }
咱们刚刚是用了两个循环,第一个循环筛选了属于字母数字的。第二次循环再判断字母数字的串有木有重复。实际上是冗余的,咱们直接在第一个循环完成便可,最终的目的是看字母数字是否回文但不必取出来再作。那样减小了一个容器和一次遍历。指针
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)一种数据结构。这里咱们能够用数组实现一下栈完成一下基本的四个方法code
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; } }
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)方法。
isLetterOrDigit(char c) toLowerCase(char c)
利用Java类库的话直接有反转方法固然它里面也是一次遍历处理,反转再比较。固然效率是比较低的能够参考
//cs为取出来的只含字母数字的字符串 String fz = cs.reverse().toString(); return cs.equals(fz);
整体来讲呢能够实现的方式有不少,关注实现自己效率来讲双指针是较优的。