剑指 Offer II 018. 有效的回文(125. 验证回文串)
题目:
思路:
【1】利用内置函数的方式
【2】利用双指针的方式,因为本质上就是回文字符串两边是相等的。
【3】基于双指针上面做位运算进行优化加快效率
【基于位运算的大小写转换技巧】
观察如下四个字母的ASCII码值。
'A': 65 = 1000001
'a': 97 = 1100001
'Z': 90 = 1011010
'z': 122 = 1111010
可以发现大小写之间只差了100000,即十进制的32。
于是对于字符ch有:
ch ^ 32 大小写反转
ch | 32 大写转小写
ch & ~32 小写转大写
代码展示:
基于双指针上面做位运算进行优化:
//时间1 ms击败100% //内存41.4 MB击败69.97% class Solution { public boolean isPalindrome(String s) { int l = 0, r = s.length() - 1; char[] arr = s.toCharArray(); while(l < r){ while(l < r && !isValid(arr[l])) l++; while(l < r && !isValid(arr[r])) r--; if(arr[l] != arr[r] && arr[l] != (arr[r] ^ 32)){ return false; } l++; r--; } return true; } private boolean isValid(char x){ int val = x - '0'; if(val <= 9 && val >= 0) return true; // 是数字 val = x - 'a'; if(val <= 25 && val >= 0) return true; // 是小写字母 val = x - 'A'; if(val <= 25 && val >= 0) return true; // 是大写字母 return false; } }
利用双指针的方式:
//时间2 ms击败93.44% //内存41 MB击败98.93% class Solution { public boolean isPalindrome(String s) { int n = s.length(); int left = 0, right = n - 1; while (left < right) { //两个指针如果遇到不是数字或者字母的就跳过 while (left < right && !Character.isLetterOrDigit(s.charAt(left))) ++left; while (left < right && !Character.isLetterOrDigit(s.charAt(right))) --right; //比较字符是否相等(这里面应把大写的也转换成小写) if (left < right) { if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) { //遇到不同则不是回文字符串 return false; } ++left; --right; } } return true; } }
利用内置函数的方式:
//时间4 ms击败36.31% //内存41.4 MB击败70.97% class Solution { public boolean isPalindrome(String s) { StringBuffer sgood = new StringBuffer(); int length = s.length(); //先单次遍历 for (int i = 0; i < length; i++) { char ch = s.charAt(i); //将是字符和数字的挑出来 if (Character.isLetterOrDigit(ch)) { //转为小写后塞入 sgood.append(Character.toLowerCase(ch)); } } //复制出反转的副本 StringBuffer sgood_rev = new StringBuffer(sgood).reverse(); //两者比较,相等的就是回文字符串 return sgood.toString().equals(sgood_rev.toString()); } }