【问题标题】:Space complexity of finding non-repeating character in string在字符串中查找非重复字符的空间复杂度
【发布时间】:2019-12-14 03:17:28
【问题描述】:

这是一个简单的算法练习。问题是返回第一个非重复字符。例如,我有这个字符串:'abbbcdd',答案是'a',因为'a' 出现在'c' 之前。如果没有找到任何重复的字符,它将返回'_'

我的解决方案工作正常,但我的问题是关于性能。问题陈述说:“编写一个只迭代字符串一次并使用 O(1) 额外内存的解决方案。”

这是我的代码:

console.log(solution('abbbcdd'))

function solution(str) {
  let chars = buildCharMap(str)
  for (let i in chars) {
    if (chars[i] === 1) {
      return i
    }
  }
  return '_'
}

function buildCharMap(str) {
  const charMap = {}
  for (let i = 0; i < str.length; i++) {
    !charMap[str[i]] ? charMap[str[i]] = 1 : charMap[str[i]]++
  }
  return charMap
}

我的答案是否满足空间复杂度的要求?

【问题讨论】:

  • 构建字符映射是O(N),因为你正在循环你的字符串,它的长度可以是N。不是O(1)。除非你知道字符串长度总是长度不变
  • O(1) 是不可能的,因为你必须遍历字符串的每个字符以某种方式,所以最坏的情况是你必须至少执行n操作,其中n是字符串的长度
  • 它说 O(1) 额外的内存。它说空间限制必须是 O(1),而不是运行时间。这意味着您不能将字符串的副本存储在变量等中。空间复杂度与时间复杂度不同
  • @sinanspd 回文?
  • 这实际上取决于有关您未包含在问题中的问题的更多详细信息。字符串是否由固定大小的字母组成(例如,只有小写字母)?如果是这样,对象的辅助空间是 O(1),而不是 O(n)。

标签: javascript performance big-o space-complexity


【解决方案1】:

时间复杂度很简单:你有一个对长度为 n 的字符串的循环,另一个对一个严格最多有 n 个键的对象的循环。循环内的操作耗时O(1),循环是连续的(不是嵌套的),所以运行时间是O(n)。

空间复杂度稍微微妙一些。例如,如果输入是数字列表而不是字符串,那么我们可以直截了当地说 charMap 在最坏的情况下占用 O(n) 空间,因为列表可能不同。但是,对于字符串的问题,我们必须知道,这些字符串可以由有限的字符组成。如果该字母的大小为 a,那么您的 charMap 对象最多可以有 a 个键,因此空间复杂度为 O(min(a, n)).

该字母在问题中通常是明确的 - 例如,如果输入保证只包含小写字母,或者只包含字母和数字。否则,字符串由 Unicode 字符(或在旧语言中为 ASCII 字符)构成的事实可能是隐含的。在前一种情况下,a = 26 或 62。在后一种情况下,a = 65,536 或 1,112,064,具体取决于我们是否计算 代码单元代码点,因为 Javascript 字符串被编码为 UTF-16。无论哪种方式,如果 a 是一个常数,那么 O(a) 空间就是 O(1) 空间——尽管它可能是一个相当大的常数。

这意味着在实践中,您的算法确实使用 O(1) 空间。理论上,如果问题陈述指定一个固定的字母表,它使用 O(1) 空间,否则使用 O(min(a, n)) 空间;不是 O(n) 空间。假设前者,那么您的解决方案确实满足问题的空间复杂度要求。

这提出了一个问题,为什么在分析数字列表上的算法时,我们同样不会说 Javascript 数字具有由 IEEE 754 specification 定义的用于浮点数的有限“字母”。答案有点哲学。我们使用抽象的计算模型分析运行时间和辅助空间,这些模型通常假设数字、列表和其他数据结构对其大小没有固定限制。但是即使在那些模型中,我们假设字符串是由一些字母组​​成的,如果字母在问题中没有固定,那么我们让字母大小是一个变量a,我们假设它独立于 n。这是分析字符串算法的明智方法,因为字母大小和字符串长度在我们通常感兴趣的问题中是独立的。

【讨论】:

  • "使用抽象的计算模型,通常假设数字可以任意大" - 实际上,在大多数计算模型中,数字(准确地说是整数)的大小限制为能够索引到最大的输入。换句话说,对于输入大小n,每个单独值的位数限制为O(log n)
  • 我接受这一点,但日志 n 仍然是“任意大”,因为 n 是任意大的。对于不涉及任何列表的数论算法,我们倾向于假设整数可以任意大,但它们不占用恒定空间,并且像 +* 这样的算术运算不占用恒定的时间。
  • 我已将“可以任意大”更改为“对其大小没有固定限制”,这样可以减少误导性。
  • 谢谢。我认为常见的术语是“任意但固定”。
猜你喜欢
  • 2020-07-31
  • 2017-06-12
  • 2018-12-10
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 2013-09-25
  • 1970-01-01
相关资源
最近更新 更多