给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串
示例 2:
输入: "race a car"
输出: false
解释:"raceacar" 不是回文串
提示:
1 <= s.length <= 2 * 105
字符串 s 由 ASCII 字符组成
前置知识点:
golang没有while、do……while循环,用for true表示死循环
s[i]可以直接遍历字符串s
字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。
Go 语言的字符有以下两种:
- 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。
- 另一种是 rune 类型,代表一个 UTF-8 字符。当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。rune 类型实际是一个 int32。
文字题解
前言
本题考查的是语言中常用字符(串)相关 API 的使用。本题解会给出解题思路以及参考代码,如果代码中有读者不熟悉的 API,可以自行查阅资料学习。
方法一:筛选 + 判断
最简单的方法是对字符串 ss 进行一次遍历,并将其中的字母和数字字符进行保留,放在另一个字符串sgood 中。这样我们只需要判断sgood 是否是一个普通的回文串即可。
判断的方法有两种。第一种是使用语言中的字符串翻转 API 得到 sgood 的逆序字符串 sgood_rev,只要这两个字符串相同,那么sgood 就是回文串。
class Solution {
public boolean isPalindrome(String s) {
//StringBuffer又被称为字符缓冲区,把它当成一个字符串去操作,只不过它与string相比是可以修改内容的。
//1、StringBuffer的内容和长度都是可以改变的,String却不可以。
//2、String创建每一个字符串都会在常量池开辟一个新的空间。而StringBuffer会提前给出容量,可以重新进行字符串拼接,而不会重新开辟空间。
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());
}
}
第二种是使用双指针。
初始时,左右指针分别指向sgood 的两侧,随后我们不断地将这两个指针相向移动,每次移动一步,并判断这两个指针指向的字符是否相同。当这两个指针相遇时,就说明sgood 是回文串。
class Solution {
public boolean isPalindrome(String s) {
//StringBuffer又被称为字符缓冲区,把它当成一个字符串去操作,只不过它与string相比是可以修改内容的。
//1、StringBuffer的内容和长度都是可以改变的,String却不可以。
//2、String创建每一个字符串都会在常量池开辟一个新的空间。而StringBuffer会提前给出容量,可以重新进行字符串拼接,而不会重新开辟空间。
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));
}
}
int n = sgood.length();
int left = 0, right = n - 1;
while(left < right){
if(sgood.charAt(left) != sgood.charAt(right)){
return false;
}
left++;
right--;
}
return true;
}
}
func isPalindrome(s string) bool {
var sgood string
for i := 0; i < len(s); i++{
if isalnum(s[i]){
sgood += string(s[i])
}
}
n := len(sgood)
sgood = strings.ToLower(sgood)
for i := 0; i < n / 2; i++{
if sgood[i] != sgood[n - i - 1]{
return false
}
}
return true
}
func isalnum(ch byte) bool{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
}
方法二:在原字符串上直接判断
我们可以对方法一中第二种判断回文串的方法进行优化,就可以得到只使用 O(1) 空间的算法。
我们直接在原字符串 s 上使用双指针。在移动任意一个指针时,需要不断地向另一指针的方向移动,直到遇到一个字母或数字字符,或者两指针重合为止。也就是说,我们每次将指针移到下一个字母字符或数字字符,再判断这两个指针指向的字符是否相同。
func isPalindrome(s string) bool {
s = strings.ToLower(s)//大写转换为小写
left, right := 0, len(s) - 1
for left < right{
for left < right && !isalnum(s[left]){//这是一个循环,只要left < right且s[left]不是数字或字母就执行
left++
}
for left < right && !isalnum(s[right]){
right--
}
//left >= right || 左右执行对应的元素符合要求
if left < right{
if s[left] != s[right]{
return false
}
left++
right--
}
}
return true
}
func isalnum(ch byte) bool{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
}