加载中...
125-验证回文串(Valid Palindrome)
发表于:2021-12-03 | 分类: 简单
字数统计: 260 | 阅读时长: 1分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/valid-palindrome

英文原文

A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.

Given a string s, return true if it is a palindrome, or false otherwise.

 

Example 1:

Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.

Example 2:

Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.

Example 3:

Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.

 

Constraints:

  • 1 <= s.length <= 2 * 105
  • s consists only of printable ASCII characters.

中文题目

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

 

示例 1:

输入: "A man, a plan, a canal: Panama"
输出: true
解释:"amanaplanacanalpanama" 是回文串

示例 2:

输入: "race a car"
输出: false
解释:"raceacar" 不是回文串

 

提示:

  • 1 <= s.length <= 2 * 105
  • 字符串 s 由 ASCII 字符组成

通过代码

高赞题解

📺 视频题解

...5. 验证回文串 - Lizzi.mp4

📖 文字题解

前言

本题考查的是语言中常用字符(串)相关 API 的使用。本题解会给出解题思路以及参考代码,如果代码中有读者不熟悉的 API,可以自行查阅资料学习。

方法一:筛选 + 判断

最简单的方法是对字符串 $s$ 进行一次遍历,并将其中的字母和数字字符进行保留,放在另一个字符串 $\textit{sgood}$ 中。这样我们只需要判断 $\textit{sgood}$ 是否是一个普通的回文串即可。

判断的方法有两种。第一种是使用语言中的字符串翻转 API 得到 $\textit{sgood}$ 的逆序字符串 $\textit{sgood_rev}$,只要这两个字符串相同,那么 $\textit{sgood}$ 就是回文串。

[sol11-C++]
class Solution { public: bool isPalindrome(string s) { string sgood; for (char ch: s) { if (isalnum(ch)) { sgood += tolower(ch); } } string sgood_rev(sgood.rbegin(), sgood.rend()); return sgood == sgood_rev; } };
[sol11-Python3]
class Solution: def isPalindrome(self, s: str) -> bool: sgood = "".join(ch.lower() for ch in s if ch.isalnum()) return sgood == sgood[::-1]
[sol11-Java]
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()); } }

第二种是使用双指针。初始时,左右指针分别指向 $\textit{sgood}$ 的两侧,随后我们不断地将这两个指针相向移动,每次移动一步,并判断这两个指针指向的字符是否相同。当这两个指针相遇时,就说明 $\textit{sgood}$ 时回文串。

[sol12-C++]
class Solution { public: bool isPalindrome(string s) { string sgood; for (char ch: s) { if (isalnum(ch)) { sgood += tolower(ch); } } int n = sgood.size(); int left = 0, right = n - 1; while (left < right) { if (sgood[left] != sgood[right]) { return false; } ++left; --right; } return true; } };
[sol12-Python3]
class Solution: def isPalindrome(self, s: str) -> bool: sgood = "".join(ch.lower() for ch in s if ch.isalnum()) n = len(sgood) left, right = 0, n - 1 while left < right: if sgood[left] != sgood[right]: return False left, right = left + 1, right - 1 return True
[sol12-Golang]
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-1-i] { return false } } return true } func isalnum(ch byte) bool { return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') }
[sol12-Java]
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)); } } int n = sgood.length(); int left = 0, right = n - 1; while (left < right) { if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))) { return false; } ++left; --right; } return true; } }

复杂度分析

  • 时间复杂度:$O(|s|)$,其中 $|s|$ 是字符串 $s$ 的长度。

  • 空间复杂度:$O(|s|)$。由于我们需要将所有的字母和数字字符存放在另一个字符串中,在最坏情况下,新的字符串 $\textit{sgood}$ 与原字符串 $s$ 完全相同,因此需要使用 $O(|s|)$ 的空间。

方法二:在原字符串上直接判断

我们可以对方法一中第二种判断回文串的方法进行优化,就可以得到只使用 $O(1)$ 空间的算法。

我们直接在原字符串 $s$ 上使用双指针。在移动任意一个指针时,需要不断地向另一指针的方向移动,直到遇到一个字母或数字字符,或者两指针重合为止。也就是说,我们每次将指针移到下一个字母字符或数字字符,再判断这两个指针指向的字符是否相同。

[sol2-C++]
class Solution { public: bool isPalindrome(string s) { int n = s.size(); int left = 0, right = n - 1; while (left < right) { while (left < right && !isalnum(s[left])) { ++left; } while (left < right && !isalnum(s[right])) { --right; } if (left < right) { if (tolower(s[left]) != tolower(s[right])) { return false; } ++left; --right; } } return true; } };
[sol2-Python3]
class Solution: def isPalindrome(self, s: str) -> bool: n = len(s) left, right = 0, n - 1 while left < right: while left < right and not s[left].isalnum(): left += 1 while left < right and not s[right].isalnum(): right -= 1 if left < right: if s[left].lower() != s[right].lower(): return False left, right = left + 1, right - 1 return True
[sol2-Golang]
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++ } for left < right && !isalnum(s[right]) { 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') }
[sol2-Java]
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; } }

复杂度分析

  • 时间复杂度:$O(|s|)$,其中 $|s|$ 是字符串 $s$ 的长度。

  • 空间复杂度:$O(1)$。

统计信息

通过次数 提交次数 AC比率
298056 631672 47.2%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言

相似题目

题目 难度
回文链表 简单
验证回文字符串 Ⅱ 简单
上一篇:
114-二叉树展开为链表(Flatten Binary Tree to Linked List)
下一篇:
136-只出现一次的数字(Single Number)
本文目录
本文目录