The time complexity of this code is: lengthOfLongestSubstring

huangapple go评论59阅读模式
英文:

What is the time complexity of this code? lengthOfLongestSubstring

问题

这段代码的时间复杂度分析如下:

  • 外部循环遍历字符串,它运行了 n 次,其中 n 是输入字符串的长度。
  • 内部循环出现在以下情况下:当当前字符是一个重复字符时,内部循环会运行,并且它的迭代次数取决于当前字符和前一个相同字符之间的字符数量。在最坏的情况下,内部循环可能运行 (n - m) * (m-1) 次,其中 m 是唯一字符的数量。

因此,整个代码的时间复杂度可以表示为 O(n * (n - m) * (m-1))。

根据这个时间复杂度分析,这段代码的复杂度可能会受到唯一字符数量 m 的影响。如果 m 较小,那么复杂度接近于 O(n^2),如果 m 较大,那么复杂度可能更接近于 O(n^3)。因此,这段代码在某些情况下可能不够高效。

请注意,这只是一种估计,实际性能可能会受到具体输入数据的影响。如果要改进时间复杂度,您可能需要重新考虑算法的设计。

英文:

Could you please help me with the time complexity of the code below?

This is a leet code problem - the function should take a string as input and return the length of the longest substring with non-repeating characters:

  • input "abcabcbb" returns 3 as answer is 'abc'
  • input "bbbbb" returns 1 as answer is 'b'
  • input "pwwkew" returns 3 as answer is 'wke'

This can be solved with a sliding window technique which if implemented well is O(n). My initial solution shown below is sliding windowish, but my solution is not O(n) as there is an inner loop triggering sometimes and this inner loop is not required at all.

In short there is a nested loop, outer loop runs for every character of the input string. The inner loop will run every time a duplicate character is hit, and it will run as many times as the number of characters between the current character and the previous occurence of this character, so:

  • input "abcabcbb", outer loop will execute 8 times as there are 8
    characters, inner loop will trigger when it hits the second occurence
    of letter 'a' ("abcabcbb") and will run 2 times for b, c
    (letters in-between), then will trigger for second occurence of
    letter 'b' ("abcabcbb") and will run 2 times for c, a, then
    will trigger for letter 'c' ("abcabcbb") and run 2 times
    for a, b, then again letter 'b' ("abcabcbb") and run once
    for c. It will then hit the final letter "b" which is again a
    duplicate, but since there are no characters in-between, it will not
    execute any loop.
  • I assume the worst case is when I just keep repeating a string. With
    input string "abcdefghabcdefgh" or more readable, "abcdefgh +
    abcdefgh" outer would execute 16 times for every character, inner
    loop would run 8 times when it starts hitting the duplicate letters,
    each time with 7 iterations.
  • So if we switch "abcdefgh" to large or infinite nr. of unique characters put together (m), and the full input string is (m + m + m + ...repeated infinitely many times), and the input length is the letter n, then:
  • outer loop: runs n times
  • inner loop: runs (n - m) * (m-1) // I'm just looking at the previous examples and the relationships there
  • n * ((n-m) * (m-1)) // put together
  • n * ((n-m) * (m)) // removing -1 constant
  • n * (nm - m^2) // simplifying
  • So O(n * (nm - m^2))? Or just simple O(n^2)? Or maybe O(n * m)? What is the right answer?

Code:

var lengthOfLongestSubstring = function(str) {
    // Create storage object for caching
    let storage = {
        longestSubStringLength: 0,
        longestSubString: 0,
        cache: {
            subString: ''
        }
    };
    // Loop through string
    for (let i = 0; i < str.length; i++) {
        let char = str[i];
        if (!storage.cache[char] && storage.cache[char] !== 0) {
            // If current letter is not in storage, add it and extend current substring
            storage.cache[char] = i;
            storage.cache.subString += char;
        } else {
            // If current letter is already in storage, start a new round
            let previousCache = storage.cache;
            storage.cache = {
                subString: ''
            };
            if (previousCache[char] + 1 !== i) { // If there are letters in-between
                storage.cache.subString = str.substring(previousCache[char] + 1, i);
                for (let j = previousCache[char]; j < i; j++) {
                    storage.cache[str[j]] = j;
                }
            }
            storage.cache[char] = i;
            storage.cache.subString += char;
        }
        // If current substring is the longest, update it in storage
        if (storage.cache.subString.length > storage.longestSubStringLength) {
            storage.longestSubStringLength = storage.cache.subString.length;
            storage.longestSubString = storage.cache.subString;
        }
    }
    return storage.longestSubStringLength;
};

答案1

得分: 1

以下是您要翻译的内容:

我们可以对这个 Map 版本进行性能测试

时间复杂度为 O(n),因为只需一次遍历字符串。

空间复杂度为 O(min(m, n)),其中 m 是字符集的大小,因为需要在 Map 中存储字符及其索引。

但这个版本更易读

const lengthOfLongestSubstring = str => {
    let cnt = 0;
    let n = str.length;
    let answer = 0;
    let map = new Map(); // 用于存储字符串及其长度
    for (let start = 0, end = 0; end < n; end++) { // 滑动窗口
        // 如果字符已经在 Map 中,则移动 start
        if (map.has(str[end])) start = Math.max(map.get(str[end]), start);
        answer = Math.max(answer, end - start + 1); // 最长子字符串
        map.set(str[end], end + 1);
        cnt++
    }
    return [str, `查找次数: ${cnt} 答案:`, "答案", answer];
}
["abcabcbb", "bbbbb", "pwwkew", "abcdefghabcdefgh"].forEach(str => console.log(lengthOfLongestSubstring(str).join(" ")))
英文:

We could do jsperf on this Map version

Time complexity of O(n) because a single pass through the string.

Space complexity is O(min(m, n)), where m is the size of the character set, due to storing the characters and their indices in a map.

It is however a lot more readable

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const lengthOfLongestSubstring = str =&gt; {
    let cnt = 0;
    let n = str.length;
    let answer = 0;
    let map = new Map(); // to store the strings and their length
    for (let start = 0, end = 0; end &lt; n; end++) { // slide
      // move start if the character is already in the map
      if (map.has(str[end])) start = Math.max(map.get(str[end]), start);
      answer = Math.max(answer, end - start + 1); // longest string
      map.set(str[end], end + 1);
      cnt++
    }
    return [str, `lookups: ${cnt} lookups:`, &quot;answer&quot;, answer];
  }
  [&quot;abcabcbb&quot;, &quot;bbbbb&quot;, &quot;pwwkew&quot;, &quot;abcdefghabcdefgh&quot;].forEach(str =&gt; console.log(lengthOfLongestSubstring(str).join(&quot; &quot;)))

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年5月17日 19:19:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76271523.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定