String 为什么我们可以';t在一次通过时可靠地测试回文

String 为什么我们可以';t在一次通过时可靠地测试回文,string,algorithm,memory,palindrome,automata,String,Algorithm,Memory,Palindrome,Automata,我偶然发现了“回文”的概念。我试图通过阅读维基百科来理解 这段话引起了我的注意 这意味着一台数量有限的计算机是不可能的 一次通过测试回文是否可靠 我想测试一个给定的字符串是否是“回文”是非常直接的吗?我拿出了一个快速代码 public class Utils { private static final String SPECIAL_CHARACTERS_REGEX = "[\\s!,]"; private static String removeSpecialCharact

我偶然发现了“回文”的概念。我试图通过阅读维基百科来理解

这段话引起了我的注意

这意味着一台数量有限的计算机是不可能的 一次通过测试回文是否可靠

我想测试一个给定的字符串是否是“回文”是非常直接的吗?我拿出了一个快速代码

public class Utils {
    private static final String SPECIAL_CHARACTERS_REGEX = "[\\s!,]";

    private static String removeSpecialCharacters(String string) {
        return string.replaceAll(SPECIAL_CHARACTERS_REGEX, "");
    }

    public static boolean isPalindrome(String string) {
        String str = string.toLowerCase();
        str = removeSpecialCharacters(str);

        if (str.isEmpty()) {
            return false;
        }

        int head = 0;
        int tail = str.length() - 1;
        while (head < tail) {
            char h = str.charAt(head);
            char t = str.charAt(tail);

            if (h != t) {
                return false;
            }

            head++;
            tail--;
        }

        return true;
    }
}

如果是这样的话,我可以知道为什么维基百科说一次通过测试回文是不可能的吗?我是否忽略了什么?

如果字符串长度为n,则代码使用O(log(n))存储(索引
需要O(log(n))位)。因此,您的程序需要无限量的内存才能测试任意长的字符串


将复杂性分析应用于实际代码是困难的,而且通常在理论上并不可靠:显然,在Java中,头和尾都是整数和32位长。但是复杂性分析处理的是任意大的输入,而不仅仅是真正的编程语言支持的所有实际用途所需的输入,而且这种差异可能很难协调(如这里所示)。

您刚刚错过了引用行前面的第一行,它说:-

在自动机理论中,给定字母表中所有回文的集合 是一种典型的与上下文无关但不依赖上下文的语言 普通的

在这里,他们讨论的是列出给定字母表上所有可能的回文

让我们来谈谈二进制字母表,A={0,1}。考虑到语言->字母表A上的回文数。回文字符串可以是无限多的,比如1,0,11,00101111,…等等

对于回文语言,至少不可能获得中间元素的概念,并在有限的内存系统中以相同的单次传递将其保存在内存(track)中。为此,您需要跟踪正在计算的字符串的各种字符,并且如何确定传入的字符与您访问的字符相反,仅在有限内存系统中的一次传递中

维基百科还指出:-

此外,回文集可能无法通过测试进行可靠测试 确定性下推自动机。当从中读取回文时 从左到右,本质上不可能找到“中间” 直到整个单词被完全阅读

这种由所有这些字符串组成的语言不能在有限内存系统中一次计算,因此,由于有限内存的限制,不能成为常规语言(常规语言可以定义为由有限自动机识别的语言---
此语言在有限内存系统中无法识别,因为有限内存系统不能有多个过程)因此,该语言无法计算所有回文字符串集。因此,它显然是有限内存系统的一个例子

这个问题又回到了自动机理论的一个著名问题:-

对于语言E,
E={0^i 1^j|i>j}
是不规则的。因此,它不能在内存有限的机器上被证明。你需要泵引理定理来证明给定的语言是不规则的。然后,你需要把下推自动机放在这里。但是,这也有它的局限性(这里不要讨论它)

此外,下一行显然打算说,拥有巨大内存和涉及多个过程的最新技术的现代计算机将很容易实现同样的功能-->

(对于现代计算机的实际用途,此限制将 仅适用于非常长的字母序列。) //当现代计算机内存耗尽时 检查回文


问题不在于检查内存中已经存在的字符串是否是回文。如果可以将该字符串读入内存,则可以轻松完成检查,但通过将该字符串读入内存,已经用完了一次检查,因此该检查是第二次检查

但这只有在整个字符串都能放入内存的情况下才能起作用。因为前提是内存是有限的,这意味着你无法验证长度超过内存容量的字符串是否是回文,这就是你引用的句子所说的


相比之下,对于任意长的字符串,您可以使用有限内存进行大量检查。例如,您可以检查字符串的长度是否可以被5整除。您可以检查字符串中的每个
a
是否紧跟着a
b
。通常,您可以检查字符串是否匹配任何正则表达式(这里,我指的是数学意义上的正则表达式,而不是“正则表达式”库所识别的模式。)但是,由于您无法使用正则表达式描述所有回文集,因此您无法在一次传递中验证任意长的字符串是否是回文,仅使用有限的内存。

我可以知道哪个测试用例产生错误的结果吗?
abcdedcba
是回文中的一个,它没有任何意义吗?程序可以这是一个有意义的句子吗?他们不是说在一个给定的字母字符串中列出所有可能的回文。他们实际上是在说,如果我们只能像有限自动机那样访问字符串,即每次读取一个字符,只存储cur,就可以识别给定的字符串是否是回文租金状态(一个有界大小的整数),在到达末尾之前不知道输入长度。给定字母表中的所有回文集(Wikipedia页面正在讨论的内容)与给定字母字符串中的所有回文集(您正在讨论的内容)非常不同。字母表中的所有回文集{a,B}是A,B,AA,BB,ABA,BAB,ABBA,…,即。,
public static void main(String[] args) {
    String s = "";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // false

    s = "1";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // true

    s = "12";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // false

    s = "123";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // false

    s = "taco cat";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // true

    s = "A man, a plan, a canal, Panama!";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // true

    s = "Amor, Roma";
    System.out.println(s + " -> " + Utils.isPalindrome(s)); // true
}