高效的 Java 语言构造来检查字符串是否为 pangram?

Efficient Java language constructs to check if string is pangram?

到目前为止,我已经想到了这个。我试图最小化字符串操作并将解决方案隔离到内置数据类型、数组和整数操作。

我正在 java 中寻找更优雅的方法来检查 pangram 字符串。

优雅,代码行数最少,也欢迎其他高效算法。

请提供没有 lambda 表达式的建议。

    private static boolean isPangrams(String ip) {

        char[] characterArray = ip.toLowerCase().toCharArray();
        int map[] = new int[26];
        int sum = 0;

        for(char current : characterArray) {

            int asciiCode = (int) current;
            if (asciiCode >= 97 && asciiCode <= 122) {

                if (map[122 - asciiCode] == 0) {

                    sum += 1;
                    map[122 - asciiCode] = 1;
                }
            }
        }

        return sum == 26;
    }

如果您发现,您可以使用 return 错误语句停止整个方法 map[122 - asciiCode] 不等于零,因为从那以后它就不再是 pangram 了,你省去了 for() 的其余部分——我说得对吗? 我知道这不是您期望的改进(尤其是只有 26 个步骤),而是我想到的东西

        if (map[122 - asciiCode] == 0) {

            sum += 1;
            map[122 - asciiCode] = 1;
        } else return false;

最有效的解决方案O(n)时间复杂度:

  1. 遍历字符串并将每个字母放入HashMap (key: letter, value: count)
  2. 遍历地图并检查字母表中的每个字母

如果你想要一个难以理解的几行回答:

private static boolean isPangrams(String ip) {
  return 26== (new HashSet(Arrays.asList(ip.toUpperCase().replaceAll("[^A-Z]", "").toCharArray()))).size();
}

解释:

  1. 将字符串设为大写(以处理 'a' 和 'A' 相同)
  2. 删除除 A、B ... Z 之外的所有字符
  3. 将其转换为 char[]
  4. 将数组转换为 Collection
  5. 将集合添加到 Set 以摆脱所有双胞胎
  6. 测试集合的大小。

您应该意识到这段代码不易阅读且性能不佳。

您可以为此使用按位运算:

private static boolean isPangrams(String ip) {
    int flags = 0;
    for(char current : ip.toLowerCase().toCharArray()) {
        if (current >= 'a' && current <= 'z') {
            flags |= 0x01<<(current-'a');
        }
    }
    return flags == 0x3ffffff;
}

jDoodle

代码的工作原理如下:我们考虑一个 int,它是一个 32 位数字。最多 26 位的每一位都是一个标志(可以这么说 boolean)。最初所有标志都是 false 因为我们用 0 初始化 flags

现在我们遍历字符串的字符。如果字符是小写字母,我们将对应标志的flag设置为true(不管之前是否设置为true

最后我们检查最低26位是否都设置为true。如果是这样,flags 等于 0x3ffffff(这是一个等于 1111111111111111111111 二进制的十六进制数。如果是这样,我们 return true。否则我们 return false.

通常按位运算比 if 语句和布尔值快,所以我希望这个程序会快很多。

如果字符串在 int 变量中包含给定字母,则可以 'pack' 数据。

static boolean pangram (String s) {
    int check = 0;
    String lowerCase = s.toLowerCase();
    for (int i = 0; i < lowerCase.length(); i++) {
      char ch = lowerCase.charAt(i);
      if (ch >= 'a' && ch <= 'z') {
        check |= (1 << s.charAt(i) - 'a');
      }
    }
    return check == 67108863;
  }

最后的幻数是0b00000011111111111111111111111111