[蓝桥杯每日一题]验证回文串

验证回文串

题目描述

LCR 018. 验证回文串

简单

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

本题中,将空字符串定义为有效的 回文串 。

示例 1:

输入: s = “A man, a plan, a canal: Panama”
输出: true
解释:“amanaplanacanalpanama” 是回文串
示例 2:

输入: s = “race a car”
输出: false
解释:“raceacar” 不是回文串

提示:

1 1 1 < = <= <= s.length < = <= <= 2 ∗ 1 0 5 2 * 10^5 2105
字符串 s 由 ASCII 字符组成

语言: C语言

bool isPalindrome(char* s) {

}

语言:C++

class Solution {
public:
    bool isPalindrome(string s) {

    }
};

语言:Java

class Solution {
    public boolean isPalindrome(String s) {

    }
}

语言:Go

func isPalindrome(s string) bool {

}

语言:Python3

class Solution:
    def isPalindrome(self, s: str) -> bool:
    

官方题解

官方题解链接

前言

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

方法一:筛选 + 判断

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

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

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;
    }
};

Python3

class Solution:
    def isPalindrome(self, s: str) -> bool:
        sgood = "".join(ch.lower() for ch in s if ch.isalnum())
        return sgood == sgood[::-1]

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());
    }
}
双指针

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

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;
    }
};

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

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')
}

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∣)。由于我们需要将所有的字母和数字字符存放在另一个字符串中,在最坏情况下,新的字符串 sgood 与原字符串 s 完全相同,因此需要使用 O(∣s∣) 的空间。

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

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

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

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;
    }
};

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

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')
}

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)。

我的题解

语言:C语言

void ToLower(char* str)//转换为小写字母
{
   while (*str != '\0')
   {
       if ('A' <= *str && *str <= 'Z')
           *str += 32;
       ++str;
   }
}

bool isPalindrome(char* s)
{
   ToLower(s);
   char* begin = s;
   char* end = s;
   char* next = s;
   while (*next)
   {
       end = next++;
   }
   while (begin < end)
   {
       //不越界的情况下,排除非字母和数字的元素
       while ((*begin < '0' || '9' < *begin && *begin < 'a' || 'z' < *begin) && begin < end)
           ++begin;
       while ((*end < '0' || '9' < *end && *end < 'a' || 'z' < *end) && begin < end)
           --end;

       //只找不匹配的情况
       if (* begin != *end)
           return false;

       ++begin;
       --end;
   }
   return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值