这是一个简单的算法练习。问题是返回第一个非重复字符。例如,我有以下字符串:'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
}
我的答案符合空间复杂性的要求吗?
答案 0 :(得分:3)
时间复杂度很简单:您在一个长度为 n 的字符串上循环,而在另一个对象上严格地使用 n 键。循环内部的操作需要O(1)时间,并且循环是连续的(非嵌套),因此运行时间为O( n )。
空间复杂性稍微微妙一些。例如,如果输入是数字列表而不是字符串,那么在最坏的情况下,我们可以直接说charMap
占用O( n )空间,因为所有数字在列表中可能会有所不同。但是,对于字符串上的问题,我们必须意识到,可以由这些字符串组成的字符的字母有限。如果该字母的大小为 a ,则您的charMap
对象最多可以具有 a 键,因此空间复杂度为O(min( a < / em>, 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 ,我们认为该变量与< em> n 。这是一种分析字符串算法的明智方法,因为字母大小和字符串长度与我们通常感兴趣的问题无关。