題目地址: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);
整體來講呢能夠實現的方式有不少,關注實現自己效率來講雙指針是較優的。