Space 复杂性:使用键初始化哈希映射并单独更新其值与在循环内动态填充键、值对
Space complexity: initializing a hashmap with keys and updating its values alone vs. dynamically populating key, value pairs inside a loop
假设我有一个简单的问题,涉及 return 字符串中所有字符的出现索引。我知道您可以直接 运行 一个 for 循环并将其打印出来,但假设我必须 return 它在某些数据结构中!
其他假设:我们知道这是一个 ASCII 字符串。字符串中不存在重复字符。
我可以做两件事之一。
预先用所有可能的 128 个键初始化 hashmap 和
None
作为值。
遍历字符串并简单地更新 dictionary/hashmap
以索引作为键的值。
遍历字典元素,并删除那些键,值
值为 None
.
的对
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)
初始化一个没有键或值的 EMPTY hashmap。
遍历字符串并创建键值对。
ascii_occurrence = {}
for charIndex in string:
ascii_occurrence[string[charIndex]] = charIndex
print(ascii_occurrence)
我确定这两种情况下的时间复杂度都是 O(N),但我不确定这两种方法的 space 复杂度。
关于 space 复杂性的争论:
方法 1,我的 space 没有 "DEPEND" 输入的大小。您可以假设当您购买计算机时已经存在具有 128 个键的散列图 运行 用于此特定目的的代码。我只是更新值而不是创建新键并根据我的输入扩展散列图.在这种情况下是 O(1).
方法 2,hashmap 最初是空的,里面什么也没有,您必须通过遍历字符串来用键值对填充它。所以真的.. 你填充字典的数量取决于输入的大小。在这种情况下是 O(N)。
我的说法正确吗?
这两种方法的复杂度都是 O(N^2),这是因为您在每次迭代时都有一个索引 (string[charIndex]
)。但是,在这种情况下,您的第二种方法通常是更好的方法。但是您也可以使用字典理解以更优化的方式(根据 运行 时间)进行操作,如下所示:
ascii_occurrence = {charIndex: ind for ind, charIndex in enumerate(string)}
在这种情况下,除了不获取带有索引的字符外,您不需要将项目分配给先前创建的字典。相反,Python 将根据需要为您创建字典,这将节省您在每次迭代时调用 __setitem__
函数的时间,它本身是暂停和恢复函数框架的组合。
这段代码的复杂度在 运行 时间和内存方面当然是 O(N)。
现在,如果您正在寻找一种更优化的方法,这很容易实现,但您必须牺牲一些其他的东西。这就是说,如果你想要更少的 运行 时间,你应该放弃一些内存,反之亦然。但是如果你不想这样做,你可能想考虑在你到达这一点之前创建你的字典。您可以在创建主字符串时创建字典。您还可以在此处执行其他棘手的方法,例如通过将枚举对象直接传递给 dict
对象来直接从枚举对象创建 dict
。但在这种情况下,索引将是键,字符将成为值。
ascii_occurrence = dict(enumerate(string))
假设我有一个简单的问题,涉及 return 字符串中所有字符的出现索引。我知道您可以直接 运行 一个 for 循环并将其打印出来,但假设我必须 return 它在某些数据结构中!
其他假设:我们知道这是一个 ASCII 字符串。字符串中不存在重复字符。
我可以做两件事之一。
预先用所有可能的 128 个键初始化 hashmap 和
None
作为值。遍历字符串并简单地更新 dictionary/hashmap
以索引作为键的值。遍历字典元素,并删除那些键,值 值为
的对None
.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)
初始化一个没有键或值的 EMPTY hashmap。
遍历字符串并创建键值对。
ascii_occurrence = {} for charIndex in string: ascii_occurrence[string[charIndex]] = charIndex print(ascii_occurrence)
我确定这两种情况下的时间复杂度都是 O(N),但我不确定这两种方法的 space 复杂度。
关于 space 复杂性的争论:
方法 1,我的 space 没有 "DEPEND" 输入的大小。您可以假设当您购买计算机时已经存在具有 128 个键的散列图 运行 用于此特定目的的代码。我只是更新值而不是创建新键并根据我的输入扩展散列图.在这种情况下是 O(1).
方法 2,hashmap 最初是空的,里面什么也没有,您必须通过遍历字符串来用键值对填充它。所以真的.. 你填充字典的数量取决于输入的大小。在这种情况下是 O(N)。
我的说法正确吗?
这两种方法的复杂度都是 O(N^2),这是因为您在每次迭代时都有一个索引 (string[charIndex]
)。但是,在这种情况下,您的第二种方法通常是更好的方法。但是您也可以使用字典理解以更优化的方式(根据 运行 时间)进行操作,如下所示:
ascii_occurrence = {charIndex: ind for ind, charIndex in enumerate(string)}
在这种情况下,除了不获取带有索引的字符外,您不需要将项目分配给先前创建的字典。相反,Python 将根据需要为您创建字典,这将节省您在每次迭代时调用 __setitem__
函数的时间,它本身是暂停和恢复函数框架的组合。
这段代码的复杂度在 运行 时间和内存方面当然是 O(N)。
现在,如果您正在寻找一种更优化的方法,这很容易实现,但您必须牺牲一些其他的东西。这就是说,如果你想要更少的 运行 时间,你应该放弃一些内存,反之亦然。但是如果你不想这样做,你可能想考虑在你到达这一点之前创建你的字典。您可以在创建主字符串时创建字典。您还可以在此处执行其他棘手的方法,例如通过将枚举对象直接传递给 dict
对象来直接从枚举对象创建 dict
。但在这种情况下,索引将是键,字符将成为值。
ascii_occurrence = dict(enumerate(string))