【问题标题】:Why is my JavaScript too slow for this Scramblies task?为什么我的 JavaScript 对于这个 Scrambles 任务来说太慢了?
【发布时间】:2020-09-20 21:39:09
【问题描述】:

我正在尝试解决以下任务:

完成函数 scramble(str1, str2),如果 str1 字符的一部分可以重新排列以匹配 str2,则返回 true,否则返回 false。

我编写的代码通过了初始测试,但在最后一次尝试中失败并出现以下错误:“执行超时(12000 毫秒)”。 这里有什么问题?

function scramble(str1, str2) {
   
let array1 = str1.split("").sort(); 
let array2 = str2.split("").sort();
let count = 0;
 
for(let a = 0; a <= array1.length && count < array2.length; a++) {
    if(array2[count] === array1[a]){
      count++;  
      }
  }
  
return (count === array2.length);
}

【问题讨论】:

  • 你能添加函数返回真/假的字符串对示例吗?
  • 最终失败的测试是什么?
  • 顺便说一句,你的函数有一个小“错误”(可能它甚至没有改变返回值):a 不应该变成array1.length,它应该是a &lt; array1.length而不是a &lt;= array1.length
  • @LucaKiebel,例子是
    scramble('rkqodlw', 'world') ==> True scramble('cedewaraaossoqqyt', 'codewars') ==> True scramble('katas' , '牛排') ==> 假 

标签: javascript


【解决方案1】:

你的代码没有问题,只是通过最后一次测试太慢了。

代码中最慢的部分是排序。通过创建一个在单字符键下具有该字符数量的对象(例如,“Hello world”变为{"H": 1, "e": 1, "l": 3, "w": 1, "o": 2, "r": 1, "d": 1}。您可以使用此“one-liner”在 O(n) 中执行此操作,而无需排序即可轻松完成"函数:

function getCharFrequencies(str) {
    return str.split("").reduce(
        function(container, char) {
            (container[char] += 1) || (container[char] = 1);
            return container;
        }, 
    {});
}

然后,您可以将每个字符串传递给该函数,并将str2 中的所有字符频率与str1 中的频率进行比较,看看您是否可以将str2 转换为str1

【讨论】:

  • 感谢您的提示。您介意向我解释这部分代码吗? (container[char] += 1) || (container[char] = 1);
  • 这是一个常见的技巧,基本上是if (container[char] === undefined) container[char] = 1; else container[char] += 1的快捷方式
  • 我很难阅读您在代码上方的解释。 “通过创建一个在一个字符键下具有该字符数量的对象”是什么意思?我只是不遵守语法
【解决方案2】:

if a portion of str1 characters can be rearranged to match str2 不是说str2 必须包含str1 的所有字符吗?您的功能可能没有失败,它只是需要很长时间才能在最终测试中运行。

function scramble(str1, str2) {
    for (const letter of str2) {
        if (!str1.includes(letter)) {
            return false;
        }
    }
    return true;
}

【讨论】:

  • 不,对于 str1 = 'of'str2 = 'oo',这将返回 true,但应该返回 false,因为 offo 都不等于 oo(仅长度的排列2在这里相关)。
  • 此外,我认为 op 并没有寻找更好的实现,而是因为测试失败的实际原因(更好的实现可能是在定义 array1array2 之后的 return (array2.join('')).includes(array1.join('')) 就像在问题)。
  • 我什至不认为它真的超时了;对于输入字符串长度 m 和 n 排序可能需要 O(nlog(n) + mlog(m)) 并且循环将在 O(n) 中运行。这将需要很长的字符串才能超时(运行时间为 12 秒)。当然还有更有效的算法,比如计算每个输入字符串的字符数(生成映射c1c2),然后比较c2 中的每个条目是否与c1 中的相应计数更大或相等。
【解决方案3】:

假设两个字符串应该具有相同的大小,并且如果是这种情况,否则会留下一些字符,这应该可以:



const scramble = (str1, str2) => {
    if (str1.length !== str2.length) return false;

    const _str1 = str1.split('').sort().join('');
    const _str2 = str2.split('').sort().join('');

    if(_str1 === _str2) return true;

    return false;
}

【讨论】:

  • 其实字符串不一定要相同大小Test.assertEquals(scramble('scriptingjava','javascript'),true); Test.assertEquals(scramble('scriptsjava','javascripts'),true); Test.assertEquals(scramble('jscripts','javascript'),false); Test.assertEquals(scramble('aabbcamaomsccdd','commas'),true);
  • 好的,那么正如已经建议的那样,即使出于性能目的,正确的方法是创建一个 char => 计数的映射,因为 str1 应该至少具有相同或更高的数字每个比str2。
猜你喜欢
  • 2014-08-04
  • 1970-01-01
  • 2017-07-07
  • 2020-08-08
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
相关资源
最近更新 更多