关于python:空间复杂性:用键初始化哈希映射并单独更新其值,而不是在循环中动态填充键、值对

Space complexity: initializing a hashmap with keys and updating its values alone vs. dynamically populating key, value pairs inside a loop

假设我有一个简单的问题,返回一个字符串中所有字符出现的索引。我知道你可以直接运行一个for循环并打印出来,但是假设我必须以某种数据结构返回它!

其他假设:我们知道这是一个ASCII字符串。字符串中不存在重复字符。

我可以做两件事中的一件。

    • 使用所有可能的128个键和None作为值。

    • 遍历字符串并简单地更新dictionary/hashmap以索引作为键的值。

    • 遍历dictionary元素,并删除那些键、值值为None的对。

      1
      2
      3
      4
      5
      6
      7
      8
      ascii_occurrence = {'a': None, 'b': None, 'c': None ... char#128: None} #Initialize a hashmap with each of the 128 characters as key, and set None to its value.

      for charIndex in string:
          ascii_occurrence[string[charIndex]] = charIndex

      indexMap = {k: v for k, v in ascii_occurrence.items() if v is not None}

      print(indexMap)
    • 初始化没有键或值的空哈希映射。

    • 遍历字符串并创建键、值对。

      1
      2
      3
      4
      5
      6
      ascii_occurrence = {}

      for charIndex in string:
          ascii_occurrence[string[charIndex]] = charIndex

      print(ascii_occurrence)
  • 我对这两种情况下的时间复杂性都很确定,但是我对这两种方法的空间复杂性不确定。

    讨论空间复杂性:

    方法1,我的空间不取决于输入的大小。您可以假设当您购买计算机以运行用于此特定目的的代码时,具有128个键的hashmap已经存在。我只是更新值,而不是创建新的键,并根据输入扩展hashmap。在这种情况下,它是O(1)。

    方法2,hashmap最初是空的,其中没有任何内容,您必须通过遍历字符串用键、值对填充它。所以真的…你的字典的填充量取决于输入的大小。在这种情况下,它是O(N)。

    我的论点正确吗?


    这两种方法的复杂性是O(n^2),这是因为在每个迭代中都有一个索引(string[charIndex])。然而,在这种情况下,第二种方法通常是更好的方法。但是,您也可以使用下面的字典理解以更优化的方式(在运行时方面)进行此操作:

    1
    ascii_occurrence = {charIndex: ind for ind, charIndex in enumerate(string)}

    在这种情况下,除了不通过索引获取字符之外,您不需要将项目分配给以前创建的字典。相反,python将根据需要为您创建字典,这样可以节省您在每次迭代时调用__setitem__函数的时间,该函数本身是挂起和恢复函数帧的组合。

    从运行时和内存的角度来看,这段代码的复杂性当然是O(n)。

    现在,如果你正在寻找一种更优化的方法,这很容易实现,但是你必须牺牲一些其他的东西。也就是说,如果您想要更少的运行时,您应该放弃一些内存,反之亦然。但如果你不想这样做,你可能会考虑在你达到这一点之前创建你的字典。您可以在创建主字符串时创建字典。这里还有其他一些棘手的方法,比如通过将枚举对象直接传递给dict对象来创建dict。但在这种情况下,索引将是关键,字符将成为值。

    1
    ascii_occurrence = dict(enumerate(string))