【问题标题】:Checking whether two strings are permutations in Java (Efficiency of Hashmap vs Array)检查两个字符串是否是Java中的排列(Hashmap vs Array的效率)
【发布时间】:2016-02-01 05:42:18
【问题描述】:

我正在阅读一本编码书,试图了解更多关于 Java 的知识,并遇到了这个问题。

问题是:“给定两个字符串,编写一个方法来判断一个是否是另一个的排列。”

考虑了一分钟左右后,我决定采用 Hashmap 解决方案。我的逻辑是添加、删除和搜索都是 O(1),所以这将是一个快速的解决方案。我的代码如下:

    public static boolean isPermutation(String a, String b) {
    if(a.length() != b.length()) {
        return false;
    }
    HashMap<Character, Integer> map = new HashMap<Character, Integer>();
    for(int x = 0; x < a.length(); x++) {
        char letter = a.charAt(x);
        if(!(map.containsKey(letter))) {
            map.put(letter, 1);
        }
        else {
            int val = map.get(letter) + 1;
            map.put(letter, val);
        }
    }
    for(int y = 0; y < b.length(); y++) {
        char letter = b.charAt(y);
        if(!(map.containsKey(letter))) {
            return false;
        }
        else {
            int val = map.remove(letter) - 1;
            if(val > 0) {
                map.put(letter, val);
            }
        }
    }
    return true;
}

然而,本书使用数组作为答案。

public boolean permutation(String s, String t) {
    if (s.length() != t.length()) {
        return false;
    }
    int[] letters = new int[256];
    char[] s_array = s.toCharArray();
    for (char c : s_array) {
        letters[c]++;
    }
    for (int i = 0; i < t.length(); i++) {
        int c = (int) t.charAt(i);
        if (--letters[c] < e) {
            return false;
        }
    }
    return true;
}

我有三个问题。

首先,我想知道我的实现是否比本书的效率低 - 如果是,效率低下的原因是什么,以及是否可以纠正它们以使 Hashmap 实现更好(或至少等于)给定的数组实现。

其次,我知道我的 Hashmap 使用自动装箱将字符转换为字符。自动装箱是否会显着放缓?

第三,在我的代码中,我试图避免使用 Hashmap 的 remove() 函数。我的逻辑是,虽然理论上应该是 O(1) 来删除,但使用 put() 代替现有的键替换为新的键(在这种情况下,覆盖旧值)会更有效,因为替换将是比删除然后添加成本更低。我的逻辑正确吗?这是我应该做的事情吗?

非常感谢!

【问题讨论】:

  • "HashMap 在下面使用一个数组,所以它永远不会比正确使用数组更快":stackoverflow.com/questions/6462055/…
  • 是的,自动装箱确实会产生开销。它还有其他几个陷阱:effective-java.com/2010/05/…
  • 请注意,如果字符串可以包含任何 Unicode 字符(包括通常的 AZ、az 和西欧字母以外的其他字母),则本书的答案将不起作用,因为它只为大批。要解决此问题,letters 需要初始化为 new int[65536]。在可能的输入元素数量太大而无法使用数组的类似问题中,HashMap 是要走的路。
  • @ajb 这是我使用 Hashmap 的逻辑的一部分,我想我会节省字符串的空间。谢谢!
  • “书”示例中有一个错字:--letters[c] &lt; e 应该是 --letters[c] &lt; 0

标签: java hashmap big-o


【解决方案1】:

首先观察:Big Oh 符号不是性能的衡量标准。相反,它表明算法将如何随着变量(例如 N)趋于无穷大而扩展。

首先,我想知道我的实现是否比书中的效率低......

对它们进行基准测试!说真的,仅仅通过检查代码很难说哪种方法更快。

您的基准测试需要考虑这样一个事实,即相对性能将取决于输入;例如使用一系列不同的字符串长度进行测量。

...如果是这样,效率低下是什么...

这就是分析的用途。它会告诉您在每种方法中花费了多少时间。并且一些分析器可以测量到行号的级别:

...以及它们是否可以被纠正以使 Hashmap 实现更好(或至少等于)给定的数组实现。

这是由您来确定的……一旦您进行了基准测试和分析。

其次,我知道我的 Hashmap 使用自动装箱将字符转换为字符。自动装箱是否会显着放缓?

肯定会放缓。它应该是可测量的(或可估计的)。例如,如果您分析您的版本,您可以看到在Character 方法中花费了多少时间。

这会很重要吗?很难预测!

第三,在我的代码中,我试图避免使用 Hashmap 的 remove() 函数。 ...我的逻辑正确吗?

是的。但是您可以再次通过基准测试和/或分析来验证这一点。


说了这么多,我的>>有根据的猜测

  • 图书解决方案预分配了一个包含 256 个 ints ... 1024 字节的数组。分配一个空的HashMap 可能需要更长的时间。

  • 自动装箱、地图查找和地图插入或更新的每个字符成本可能比图书解决方案中的同等成本要高得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 2016-04-07
    • 1970-01-01
    • 1970-01-01
    • 2020-02-02
    相关资源
    最近更新 更多