leetcode
leetcode 2051 ~ 2100
验证回文串 IV

验证回文串 IV

难度:

标签:

题目描述

代码结果

运行时间: 35 ms, 内存: 16.1 MB


/*
 * 题目思路:
 * 给定一个字符串s,我们需要判断它是否是一个回文串。在这个问题中,我们需要考虑以下情况:
 * 1. 忽略大小写
 * 2. 忽略非字母和数字的字符
 * 3. 如果删除一个字符后可以成为回文串,那么返回true
 *
 * 我们可以分步进行:
 * 1. 预处理字符串,去除非字母和数字的字符,并将所有字符转换为小写
 * 2. 使用双指针法检查是否是回文串
 * 3. 如果不是回文串,尝试删除一个字符后再进行检查
 */

import java.util.stream.IntStream;

public class Solution {
    public boolean validPalindrome(String s) {
        // 预处理字符串
        String cleanedStr = s.chars()
                .filter(Character::isLetterOrDigit)
                .mapToObj(c -> String.valueOf((char) c).toLowerCase())
                .collect(Collectors.joining());

        // 检查是否为回文
        if (isPalindrome(cleanedStr)) {
            return true;
        }

        // 尝试删除一个字符后再检查
        return IntStream.range(0, cleanedStr.length())
                .anyMatch(i -> isPalindrome(cleanedStr.substring(0, i) + cleanedStr.substring(i + 1)));
    }

    private boolean isPalindrome(String s) {
        return IntStream.range(0, s.length() / 2)
                .allMatch(i -> s.charAt(i) == s.charAt(s.length() - 1 - i));
    }
}

解释

方法:

此题的目标是判断给定字符串是否可以通过至多两次修改变成回文串。解题思路是通过一次遍历的方式,从字符串的两头向中心检查字符是否相等。如果发现不相等的字符,允许减少一次修改机会(即times变量减1)。如果在遍历过程中,需要的修改次数超过2次(times变成负数),则直接返回False。如果整个遍历完成后,修改次数没有超过2次,返回True。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,为什么选择从字符串两端向中心遍历而不是从中心向两端遍历?
从字符串两端向中心遍历是因为回文串具有中心对称的特性。这种方式可以直接比较首尾字符,如果不相等,则可立即知道需要修改。而从中心向两端遍历则需先确定中心位置,对于偶数长度的字符串,这不是一个明确的单个字符,处理起来更复杂。从两端向中心遍历更直接有效地利用了回文的对称性质。
🦆
如果在某次比较中字符不相等,为什么直接减少修改次数而不是尝试其他操作,比如替换字符?
减少修改次数的逻辑是为了简化判断过程。在实际操作中,减少一次修改次数实际上隐含了进行了一次字符替换的假设,即将一个字符替换成另一个以匹配对称位置的字符。这种假设是在不实际修改字符串的情况下,快速判断能否通过有限次修改达成回文串的有效方法。
🦆
在算法中,times变量初始化为2意味着什么?是否表示可以进行两次删除操作,两次添加操作,还是两次替换操作?
times变量初始化为2表示最多允许进行两次修改操作,以使字符串变为回文串。这里的修改操作通常指的是替换操作,即将一个字符换成另一个字符。虽然理论上可以考虑删除或添加字符的操作,但在本题的上下文中,主要考虑的是替换操作,因为这是最直接处理字符不匹配的方式。
🦆
算法如何处理长度为奇数的字符串,中间的字符是否需要检查?
在长度为奇数的字符串中,中间的字符实际上没有对应的字符与之对称,因此在从两端向中心遍历的过程中不需要检查中间的字符。中间的字符不影响回文的判断,因为它总是自己与自己对称。因此,算法只检查到字符串的一半,不包括中间字符(如果存在)。

相关问题