我正在尝试确定以下函数的时间复杂度。
该功能反转字符串中单词的顺序,然后反转单词中字母的顺序。
例如:
“天是蓝色” =>“ eulb siks yks eht”
var reverseString = function(s) {
let str = s.split(' ')
let word;
let wordRev;
let result = [];
let countI = 0
let countJ = 0
//lets call this loop "i"
for(let i=str.length-1; i>=0; i--) {
word = str[i]
wordRev = ""
countI +=1
//lets call this loop "j"
for(let j=word.length-1; j>=0; j--) {
wordRev += word[j]
countJ+=1
}
result.push(wordRev)
}
return result.join(" ")
};
尽管有两个嵌套循环,但我相信时间复杂度为O(n),我将给出两个方案作为示例。
• Scenario 1:
⁃ s.length: 22
⁃ input: “thisisreallylongstring”
⁃ str: [“thisisreallylongstring”]
⁃ i loop count total: 1
⁃ j loop count total: 22
• Scenario 2
⁃ s.length = 11
⁃ input: “s t r i n g”
⁃ str: [“s”, “t”, “r”, “i”, “n”, “g”]
⁃ j loop count total: 6
⁃ i loop count total: 6
循环i和j的总数大致等于输入的长度,这使我相信即使存在两个嵌套循环,其复杂度仍为O(n)。
我的思路不对吗?
答案 0 :(得分:2)
两个因素在起作用:
您的算法本身为O(n)。在每个内部循环中处理的子字符串是不相交的。也就是说,您有两个嵌套循环,但是在内部循环中处理的字符串部分永远不会通过外部循环中的单独迭代重复进行。每个内部循环都有自己的单独子字符串,将它们加在一起时,它就是O(n)。
以这种方式附加字符串使算法为O(n ^ 2)。字符串是不可变的,因此每次调用wordRev += word[j]
都会创建一个全新的字符串。在最坏的情况下,例如对于"thisisreallylongstring"
,最终会创建"g", "gn", "gni", ...
作为中间字符串。将它们加在一起就是O(n ^ 2)。
所以总体答案是O(n ^ 2)。
答案 1 :(得分:1)
您真正关心的是内部循环运行了多少次,以及您在循环中所做的一切是否都是固定时间。在您的情况下,内部循环始终运行n
次,其中n
是句子中字母的数量。为了进行测试,您可以轻松地制作一些假句子,并实际计算循环运行的次数。因此,使用由let str = Array.from({length: 20}, ()=>'a'.repeat(20)).join(' ')
构成的句子,您会发现内部循环恰好运行了400次。您到底有多少个字母。有时您需要小心使用javascript函数,因为它们并非总是在恒定时间内运行-例如,如果您在循环中的位置处对数组进行拼接,但您似乎并未在此处执行此操作。一切都应该在线性时间内运行。所以O(n),其中n是字母数。