【问题标题】:Time Complexity for JavaScript Anagram FunctionJavaScript Anagram 函数的时间复杂度
【发布时间】:2018-06-14 15:29:42
【问题描述】:

我有一个任务来纠正一个函数,该函数将采用 2 个字符串并返回需要删除的字符数,以便使 2 个字符串相互变位。我的问题是这个函数的时间复杂度是多少,是否有更快的方法来实现相同的结果。 这是我的解决方案:

function anagramDelete(str1, str2){
    let obj1 = {}, obj2 = {};

    // Load obj1 with all characters of str1 and their count
    str1.split('').forEach((char)=> {
        if(char in obj1){
            obj1[char]++;
        } else {
            obj1[char] = 1;
        }
    });

    // Load obj2 with all characters of str1 and their count
    str2.split('').forEach((char)=> {
        if(char in obj2){
            obj2[char]++;
        } else {
            obj2[char] = 1;
        }
    });

    // Track # of chars deleted
    let numOfDeletions = 0;

    // Compare each char in obj1 w obj2 and count deletions
    for(char in obj1){
        if(obj2[char]){
            numOfDeletions += Math.abs(obj2[char] - obj1[char]);
        } else {
            numOfDeletions += obj1[char];
        }
    }
    // Compare each char in obj2 w obj1 and count deletions
    for(char in obj2){
        if(!obj1[char]){
            numOfDeletions += obj2[char];
        }
    }
    return numOfDeletions;
}

据我所知,因为有 4 个循环,所以它是 O(4n) 或只是 O(n)。我这样说是因为没有嵌套循环。它是否正确?有更好的解决方案吗?

【问题讨论】:

  • 我还是会说它的O(n)。导致 4 个 for 循环不会慢 4 倍。

标签: javascript time-complexity computer-science anagram


【解决方案1】:

您可以使用单个对象并仅对绝对值求和。

此解决方案使用字符串作为数组对象。

function anagramDelete(str1, str2) {
    var letters = {};

    Array.prototype.forEach.call(str1, char => letters[char] = (letters[char] || 0) + 1);
    Array.prototype.forEach.call(str2, char => letters[char] = (letters[char] || 0) - 1);
 
    return Object.keys(letters).reduce((r, k) => r + Math.abs(letters[k]), 0);
}

console.log(anagramDelete('anagram', 'function'));

【讨论】:

    【解决方案2】:

    您的代码是O(n + m);一般来说,人们并不太关心复杂性类中的常量。 n 是第一个字符串的长度,m 是第二个字符串的长度。

    还有: 准确地说,因为您提到了O(4n) - 我不确定这是否准确。您使用 split 函数两次,在您的情况下,这会将字符串转换为字符数组。您在分析中没有考虑到这一点。

    O(n + m) 是正确答案。

    如果你想详细分析分析,那就是O(3n + 3m)。那是因为:
    - 对于您使用的第一个字符串split (O(n)),您循环遍历每个字符 (O(n)),然后再次循环进行比较 (O(n))
    - 对于您使用的第二个字符串split (O(m)),您循环遍历每个字符 (O(m)) 并再次循环进行比较 (O(m))

    我认为您的代码是正确的。我没有检查。

    附:
    如果您对微调常量感兴趣,可以参考其他答案,理论上它们可能比您的代码更快。实际上,我认为这并不重要。

    【讨论】:

      【解决方案3】:

      不是更好,而是更短:

        function anagramDelete(str1, str2){
         const chars = {};
         var result = 0;
      
         for(const char of str1)
           chars[char] = (chars[char] || 0) +1;
      
         for(const char of str2)
           chars[char] = (chars[char] || 0) -1;
      
         for(const [char, count] of Object.entries(chars))
          result += Math.abs(count);
      
         return result;
       }
      

      【讨论】:

      • 如果chars[char] - 1 == 0变成-1会怎样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2018-05-29
      • 2015-08-01
      相关资源
      最近更新 更多