【经典算法】LeetCode 125. 验证回文串(Java/C/Python3实现含注释说明,Easy)

简介: 【经典算法】LeetCode 125. 验证回文串(Java/C/Python3实现含注释说明,Easy)
  • 作者简介:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名
  • ❤️觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论,💬支持博主,记得点个大大的关注,持续更新🤞
    ————————————————-
    首先,请注意您提供的题目链接是 LeetCode 14,但题目描述和代码实现应该对应于 LeetCode 125(验证回文串)。以下是按照您要求的格式编写的技术博客。

题目描述

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

原题:LeetCode 125. 验证回文串

思路及实现

方式一:双指针

思路

从字符串的两端向中间遍历,跳过非字母和数字的字符,比较对应的字符是否相等。

代码实现

Java版本
public boolean isPalindrome(String s) {
    int left = 0, right = s.length() - 1;
    while (left < right) {
        // 跳过非字母和数字的字符
        while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
            left++;
        }
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
            right--;
        }
        // 转换为小写并比较
        if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

说明:使用双指针从字符串两端向中间遍历,跳过非字母和数字的字符,比较对应字符(转换为小写后)是否相等。

C语言版本
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
bool isPalindrome(char *s) {
    int left = 0, right = strlen(s) - 1;
    while (left < right) {
        // 跳过非字母和数字的字符
        while (left < right && !isalnum(s[left])) {
            left++;
        }
        while (left < right && !isalnum(s[right])) {
            right--;
        }
        // 转换为小写并比较
        if (tolower(s[left]) != tolower(s[right])) {
            return false;
        }
        left++;
        right--;
    }
    return true;
}

说明:C语言版本与Java版本类似,但使用了C标准库中的函数来处理字符。

Python3版本
def isPalindrome(s: str) -> bool:
    left, right = 0, len(s) - 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 s[left].lower() != s[right].lower():
            return False
        left += 1
        right -= 1
    return True

说明:Python版本与Java版本思路相同,但语法不同。

Golang版本
func isPalindrome(s string) bool {
    left, right := 0, len(s)-1
    for left < right {
        // 跳过非字母和数字的字符
        for left < right && !isAlnum(s[left]) {
            left++
        }
        for left < right && !isAlnum(s[right]) {
            right--
        }
        // 转换为小写并比较
        if toLower(s[left]) != toLower(s[right]) {
            return false
        }
        left++
        right--
    }
    return true
}
func isAlnum(c byte) bool {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
}
func toLower(c byte) byte {
    if c >= 'A' && c <= 'Z' {
        return c + 'a' - 'A'
    }
    return c
}

说明:Golang版本也实现了双指针的逻辑,并额外定义了辅助

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串的长度。在最坏情况下,我们需要遍历整个字符串一次。
  • 空间复杂度:O(1),我们使用了常数级别的额外空间来存储指针和变量。

方式二:辅助栈

思路

我们可以使用一个栈来存储字符串的前半部分(忽略非字母和数字字符),然后逐个与字符串的后半部分(同样忽略非字母和数字字符)进行比较。

代码实现

Java版本
import java.util.Stack;
public boolean isPalindromeWithStack(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (Character.isLetterOrDigit(c)) {
            stack.push(Character.toLowerCase(c));
        }
    }
    
    for (char c : s.toCharArray()) {
        if (Character.isLetterOrDigit(c)) {
            char topChar = stack.pop();
            if (Character.toLowerCase(c) != topChar) {
                return false;
            }
        }
    }
    
    // 如果栈不为空,说明前半部分有多余字符,不是回文
    return stack.isEmpty();
}

说明:首先将字符串中的字母和数字字符(转换为小写)压入栈中,然后再次遍历字符串并与栈顶字符进行比较。

C语言版本

由于C语言没有内建的栈,我们通常会使用数组来模拟栈的行为。

#include <ctype.h>
#include <stdbool.h>
#define MAX_STACK_SIZE 1000
bool isPalindromeWithStack(char *s) {
    char stack[MAX_STACK_SIZE];
    int top = -1;
    
    for (int i = 0; s[i] != '\0'; i++) {
        if (isalnum(s[i])) {
            stack[++top] = tolower(s[i]);
        }
    }
    
    for (int i = 0; s[i] != '\0'; i++) {
        if (isalnum(s[i])) {
            if (tolower(s[i]) != stack[top--]) {
                return false;
            }
        }
    }
    
    return top == -1;
}

说明:使用数组模拟栈的行为,首先将字母和数字字符压入栈中,然后再次遍历字符串并与栈顶字符进行比较。

Python3版本

Python中的列表可以作为栈使用。

def isPalindromeWithStack(s: str) -> bool:
    stack = []
    for c in s:
        if c.isalnum():
            stack.append(c.lower())
    
    for c in s:
        if c.isalnum():
            if c.lower() != stack.pop():
                return False
    
    return len(stack) == 0

说明:Python版本使用列表作为栈,首先将字母和数字字符压入栈中,然后再次遍历字符串并与栈顶字符进行比较。

Golang版本

在Golang中,我们也可以使用切片(slice)来模拟栈。

func isPalindromeWithStack(s string) bool {
    stack := make([]byte, 0)
    for _, c := range s {
        if isAlnum(c) {
            stack = append(stack, toLower(c))
        }
    }
    
    for _, c := range s {
        if isAlnum(c) {
            topChar := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            if toLower(c) != topChar {
                return false
            }
        }
    }
    
    return len(stack) == 0
}
// isAlnum 和 toLower 函数与前面的Golang版本相同

说明:Golang版本使用切片作为栈,首先将字母和数字字符压入栈中,然后再次遍历字符串并与栈顶字符进行比较。

复杂度分析

  • 时间复杂度:O(n),其中 n 是字符串的长度。我们需要遍历整个字符串两次,一次用于压栈,一次用于比较。
  • 空间复杂度:O(n),在最坏情况下,我们需要将字符串中的所有字母和数字字符都压入栈中,因此栈的大小与字符串的长度成正比。但在实际情况中,由于我们只存储了字母和数字字符,所以空间复杂度可能会

总结

方式 优点 缺点 时间复杂度 空间复杂度
双指针法 代码简洁,时间效率高 依赖于字符串的结构,对于非回文字符串需要遍历整个字符串 O(n) O(1)
辅助栈法 逻辑清晰,易于理解 需要额外的空间来存储栈,可能不是最优解 O(n) O(n)

注意:在辅助栈法中,虽然空间复杂度是O(n),但在实际情况下,由于我们只存储了字母和数字字符,所以空间复杂度可能会低于O(n)。

相似题目

相似题目 难度 链接
LeetCode 125. 验证回文串 简单 力扣-125
LeetCode 234. 回文链表 简单 力扣-234
LeetCode 680. 验证回文字符串 Ⅱ 简单 力扣-680
LeetCode 5. 最长回文子串 中等 力扣-5
LeetCode 131. 回文分割 中等 力扣-131
LeetCode 266. 回文排列 中等 力扣-266

注意:这些题目可能不仅涉及回文字符串的验证,还可能包括回文子串、回文链表等不同的变种,但都与回文的概念相关。

欢迎一键三连(关注+点赞+收藏),技术的路上一起加油!!!代码改变世界

  • 关于我:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法公众号同名),回复暗号,更能获取学习秘籍和书籍等
相关文章
|
5月前
|
存储 Java API
【Azure 存储服务】Java Storage SDK 调用 uploadWithResponse 代码示例(询问ChatGTP得代码原型后人力验证)
【Azure 存储服务】Java Storage SDK 调用 uploadWithResponse 代码示例(询问ChatGTP得代码原型后人力验证)
|
1月前
|
Java
Java 中的注释
1. 单行注释:// 2. 多行注释:/* */ 3. 文档注释::/** **/
|
3月前
|
Java 测试技术 程序员
💡Java 零基础 | 深入理解注释的重要性与应用
【10月更文挑战第10天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
38 5
|
3月前
|
存储 网络协议 前端开发
在 Java 中如何完全验证 URL
在 Java 中如何完全验证 URL
99 8
|
3月前
|
算法 Java
LeetCode(一)Java
LeetCode(一)Java
|
4月前
|
Java API 开发者
Java 注释规范
Java中的注释规范包括单行注释(`//`)、多行注释(`/* ... */`)和文档注释(`/** ... */`)。单行注释适用于简短说明,多行注释用于较长描述,文档注释则专为自动生成API文档设计。注释应清晰明了、及时更新,避免冗余,并详细说明参数和返回值。遵循这些规范有助于提高代码的可读性和可维护性。
239 5
|
5月前
|
Java C# 容器
逻辑运算符Java代码的注释
这段代码及文字介绍了一个简单的Java程序以及Java编程的基础概念。代码展示了如何输出“Hello Word”。接着,用贴近生活的比喻解释了`package`(包)、`public`(访问修饰符)、`class`(类)、`static`(静态)和`void`(空)的概念。此外,还介绍了`System.out.println()`方法。进一步讲解了Java中的注释、数据类型(包括整型、浮点型、字符型和布尔型),变量和常量的概念,以及运算符、类型转换、赋值运算符、关系运算符与逻辑运算符等基础知识点。通过生动的例子帮助初学者更好地理解和记忆。
30 2
|
5月前
|
Java
【Java 第三篇章】注释、数据类型、运算符
【8月更文挑战第2天】 Java支持三种注释:单行(`//`)、多行(`/*...*/`)及文档注释(`/**...*/`)。它定义了八种基本数据类型,包括四种整数类型(`byte`、`short`、`int`、`long`),两种浮点类型(`float`、`double`),一种字符类型(`char`)和一种布尔类型(`boolean`)。数据类型之间可以自动转换或通过强制转换改变,但后者可能导致精度损失。Java中的运算符涵盖算术(如`+`、`-`)、赋值(如`=`)、比较(如`==`)、逻辑(如`&&`)和三目运算符等。例如,算术运算可用于执行基本数学计算,而逻辑运算符用于组合条件判断。
30 1
|
5月前
|
存储 Java
如何在 Java 中验证 ArrayList?
【8月更文挑战第23天】
47 0
|
4月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行