如何使JS功能更快/降低复杂度0(n)/提高效率

时间:2018-09-05 19:30:26

标签: javascript node.js

我正在处理HackerRank上的一些挑战,并且在使功能更快/更高效以使其在提交过程中不会超时方面遇到一些麻烦。对于很大的输入(例如,字符串长度为1000或更多),通常会超时,而我使用的循环次数使函数正常工作。我知道循环使复杂度为0(n * n)或0(n * n * n)。我理解为什么由于上述复杂性问题而导致函数超时,但是我不确定如何使函数更有效以处理更大的输入。我是一名自学成才的编码员,因此请彻底,简单地解释所有答案,以便我学习。谢谢!

这是一个示例问题:

如果满足以下两个条件之一,则将字符串称为特殊回文字符串:

  • 所有字符都相同,例如aaa。

  • 除中间字符外的所有字符都相同,例如阿达阿(acdca不会满足此规则,但aadaa会满足)

特殊回文子串是指满足这些条件之一的任何子串。给定一个字符串,确定可以从中形成多少个特殊回文子字符串。

例如,给定字符串s = mnonopoo,我们有以下特殊回文子字符串:

  • m,n,o,n,o,p,o,o
  • oo
  • non,ono,opo

功能说明

在下面的编辑器中完成substrCount函数。它应该返回一个整数,该整数表示可以从给定字符串形成的特殊回文子字符串的数量。 substrCount具有以下参数:

  • n:一个整数,字符串s的长度
  • s:一个字符串

function substrCount(n, s) {
    //if each letter is its own palindrome then can start with length for count
    let count = n;
    //space used to get the right string slices
    let space = 1;
    //so we only get full strings with the split and no duplicates
    let numberToCount = n;
    for(let i = 0; i < n; i++){
        for(let j = 0; j < n; j++){
            //slice the string into the different sections for testing if palindrome
            let str = s.slice(j, j+space);
            if(numberToCount > 0){
                //if it is an even length the all characters must be the same
                if(str.length % 2 === 0){
                    let split = str.split('');
                    let matches = 0;
                    for(let k = 0; k < split.length; k++){
                        if(split[k] === split[k+1]){
                            matches++;
                        }
                    }
                    if(matches === split.length -1){
                        count++;
                    }
                //if it is not even then we must check that all characters on either side
                //of the middle are all the same
                } else {
                    if(str.length > 1){
                        let splitMid = Math.floor(str.length / 2);
                        let firstHalf = str.slice(0, splitMid);
                        let lastHalf = str.slice(splitMid+1, str.length);
                        if(firstHalf === lastHalf){
                            if(str.length === 3){
                                count++;
                            } else {
                                let sNew = firstHalf + lastHalf;
                                let split = sNew.split('');
                                let matches = 0;
                                for(let k = 0; k < split.length; k++){
                                    if(split[k] === split[k+1]){
                                       matches++;
                                    }
                                 }
                                 if(matches === split.length -1){
                                    count++;
                                 }
                            }
                        }
                    }
                }
            }
            numberToCount--;
        }
        numberToCount = n-space;
        space++;
    }
    return count; 
}

2 个答案:

答案 0 :(得分:0)

我想出了一个我认为在性能上不太复杂的解决方案(一次循环和一次递归)

步骤

  • 分割字符串并将其插入数组
  • 先检查偶数对是否为递归
  • 接下来再次将奇数对检查为递归
  • 检查插入到最终数组中的值是否唯一(并非仅对于单个字符唯一)

请告诉我这是否是正确的解决方案,否则我们可以加快速度

const stirng = "mnonopoo";

const str = stirng.split("");
let finalArray = [];

str.forEach((x, index) => {
  if (str[index] === str[index + 1]) {
    checkEven(str, index, 1)
  }
  if (str[index - 1] === str[index + 1]) {
    checkOdd(str, index, 0)
  }
  finalArray.push(x);
})
function checkOdd(str1, index, counter) {
  if (str1[index - counter] === str1[index + counter]) {
    counter++;
    checkOdd(str1, index, counter);
  } else {
    pushUnique(finalArray, str1.slice(index - counter + 1, index + counter).join(""));
    return str1.slice(index - counter, index + counter).join("")
  }
}

function checkEven(str1, index, counter) {
  if (str1[index] === str1[index + counter]) {
    counter++;
    checkEven(str1, index, counter);

  } else {
    pushUnique(finalArray, str1.slice(index, index + counter).join(""));
    return;
  }
}
function pushUnique(array, value) {
  if (array.indexOf(value) === -1) {
    array.push(value);
  }
}
console.log(finalArray)

答案 1 :(得分:-1)

由于您只寻找特殊回文,而不是所有回文,这使得降低复杂性要容易一些,但是即使那样,仍然会有一些特殊情况,例如“ abababababababa ....”。我看不出有什么办法可以降低它的复杂性。

我会这样处理。首先将所有重复数字分组。我不确定做到这一点的最佳方法,但是我在想也许要创建一个对象数组,其对象属性为count和letter。

从totalCount为0开始。

然后,选择所有计数为1的对象,并检查它们左右的对象,如果它们具有相同的字母值,则取MAX计数,并将该值+ 1加到totalCount( +1是指单个字母本身)。如果两边的字母值都不匹配,只需加1(以单独计算字母)即可。

可以处理所有奇数回文。现在要处理偶数回文。

选择所有计数大于1的对象,并获取它们的计数值,并将1计数中的序列添加到totalCount。此公式为(count / 2)*(1 + count)。 例: 在字符串中,您需要运行4A。有特殊回文(a,a,a,a,aa,aa,aa,aaa,aaa,aaaaa),总共有10个。(4/2)*(1 + 4)= 10。 / p>

我不知道这将减少您的处理时间,但是我认为它应该减少一些处理时间。