【问题标题】:Reducing time complexity using HashMap, or is there a better method?使用HashMap降低时间复杂度,还是有更好的方法?
【发布时间】:2023-03-09 21:02:01
【问题描述】:

是的,这是我用来准备 1 月份自己的考试的旧考试。我们给出了以下方法:

public static void Oorspronkelijk()
{
    String bs = "Dit is een boodschap aan de wereld";
    int max = -1;
    char let = '*';
    for (int i=0;i<bs.length();i++) {
        int tel = 1;
        for (int j=i+1;j<bs.length();j++) {
            if (bs.charAt(j) == bs.charAt(i)) tel++;
        }

        if (tel > max) {
            max = tel;
            let = bs.charAt(i);
        }
    }

    System.out.println(max + " keer " + let);
}

问题是:

  1. 输出是什么? - 由于代码只是一种确定出现次数最多的字符的算法,因此输出为“6 keer”(6 倍空间)
  2. 这段代码的时间复杂度是多少? 很确定它是 O(n²),除非有人不这么认为?
  3. 您能否降低时间复杂度,如果可以,如何降低?

嗯,你可以。我已经收到了一些帮助并设法获得了以下代码:

public static void Nieuw()
{
    String bs = "Dit is een boodschap aan de wereld";
    HashMap<Character, Integer> letters = new HashMap<Character, Integer>();
    char max = bs.charAt(0);
    for (int i=0;i<bs.length();i++) {
        char let = bs.charAt(i);
        if(!letters.containsKey(let)) {
            letters.put(let,0);
        }

        int tel = letters.get(let)+1;
        letters.put(let,tel);

        if(letters.get(max)<tel) {
            max = let;
        }
    }

    System.out.println(letters.get(max) + " keer " + max);
}

但是,我不确定这段新代码的时间复杂度:是 O(n) 是因为您只使用了一个 for 循环,还是我们需要使用 HashMap 的 get 方法这一事实使其成为 O( n log n) ?

如果有人知道降低时间复杂度的更好方法,请告诉! :)

【问题讨论】:

  • 我不擅长确定复杂性和伤员 - 为什么 O(n^2)?我的问题点是:在第二个循环中,你迭代不是 N 次,而是(N - M,并且 M 在每次迭代中增加 1)。
  • @Vanger 表示第二个循环将执行 (1+2+3+...+N) 次,即 [(N+1)*N]/2 = (N^2 +N)/2 = O(N^2)
  • @yurib Thx :) 完全忘记了系列。

标签: java algorithm hash hashmap complexity-theory


【解决方案1】:

Hashmap 是 O(1),但在这里你也可以使用数组,因为字母的数量相当少(只有 256 个)你也可以使用数组。这也是 O(1),但速度更快,使用的内存更少,而且更简单:

String bs = "Dit is een boodschap aan de wereld";
int letters[] = new int[256];
char max = 0;
for (int i=0;i<bs.length();i++) {
    char let = bs.charAt(i);
    ++letters[let];

    if(letters[max] < letters[let]) {
        max = let;
    }
}

System.out.println(letters[max] + " keer " + max);

【讨论】:

    【解决方案2】:

    为确保 HashMap 始终具有 O(1) 的时间复杂度,您可能必须输入正确的 initialCapacity。您需要知道 bs 字符串将具有的完整域值。

    假设, 1.大写和小写分开处理。 2.字符串将只有字母和空格字符

    初始负载能力应大于,26(小写)+ 26(大写)+ 1(空格)= 53

    53 + 25%(53) = 53 + 13.25 + 2.75(缓冲)= 69。

    所以 hashmap 初始化可能如下所示,

    HashMap 字母 = new HashMap(69);

    【讨论】:

    • 这不会有太大影响,因为 69 是一个很小的数字。但对于更大的数字,你是完全正确的。
    • hashmap 的默认容量为 16,如果您不初始化任何内容。时间复杂度将从 O(1) 变为 O(5) - 因为 69/16 = 4.3...
    • O(5) = O(1),但即使这样也不正确,因为 5 不是复杂性的一个因素,而是一个恒定的开销。所以它不会影响 big-O 复杂度。
    【解决方案3】:

    新代码的时间复杂度是O(n)——这是因为hashmap查找是一个常数时间操作,常数时间操作不影响顺序。

    我可以提出的一个建议,只是一个优化(不会有很大的不同)——不是一个重大的变化,也不会影响顺序——你可以使用一个整数数组而不是哈希映射来跟踪每个字符的计数。只需使用相当于 char 的 int 值作为数组的索引即可。

    【讨论】:

      【解决方案4】:

      我认为是 O(n) 。因为在HashMap中搜索就是O(1)

      for (int i=0;i<bs.length();i++) { // O(n)
          char let = bs.charAt(i); // O(1)
          if(!letters.containsKey(let)) { // O(1)
              letters.put(let,0);
          }
      

      整体复杂度为O(n)

      【讨论】:

        【解决方案5】:

        哈希函数获取操作为 O(1),因此您的解决方案的时间复杂度为 O(n)。 你不能做得比这更好,因为任何解决方案都需要你至少阅读整个输入一次。

        【讨论】:

          猜你喜欢
          • 2011-06-15
          • 1970-01-01
          • 2014-04-21
          • 2023-03-06
          • 1970-01-01
          • 2012-07-28
          • 2016-10-07
          • 1970-01-01
          相关资源
          最近更新 更多