如何提高此Javascript /破解代码算法的性能?

时间:2018-09-07 23:38:13

标签: javascript arrays string algorithm performance

所以这是下面的问题,以及我的回答。我知道由于双嵌套的for循环,效率为O(n ^ 2),所以我想知道是否有一种方法可以改善算法/函数的大O。

//设计一种算法并编写代码以删除字符串中的重复字符,而无需使用任何其他缓冲区。注意:一个或两个其他变量都可以。不是数组的额外副本。

function removeDuplicates(str) {
    let arrayString = str.split("");
    let alphabetArray = [["a", 0],["b",0],["c",0],["d",0],["e",0],["f",0],["g",0],["h",0],["i",0],["j",0],["k",0],["l",0],["m",0],["n",0],["o",0],["p",0],["q",0],["r",0],["s",0],["t",0],["u",0],["v",0],["w",0],["x",0],["y",0],["z",0]]

    for (let i=0; i<arrayString.length; i++) {
        findCharacter(arrayString[i].toLowerCase(), alphabetArray);
    }

    removeCharacter(arrayString, alphabetArray);
};


function findCharacter(character, array) {
    for (let i=0; i<array.length; i++) {
        if (array[i][0] === character) {
        array[i][1]++;
        }
    }
} 

function removeCharacter(arrString, arrAlphabet) {
    let finalString = "";
    for (let i=0; i<arrString.length; i++) {
        for (let j=0; j<arrAlphabet.length; j++) {
            if (arrAlphabet[j][1] < 2 && arrString[i].toLowerCase() == arrAlphabet[j][0]) {
            finalString += arrString[i]
            }
        }
      } 
    console.log("The string with removed duplicates is:", finalString)
}

removeDuplicates("Hippotamuus")

4 个答案:

答案 0 :(得分:1)

相同大小写的所有字母的ASCII / Unicode字符代码是连续的。这允许进行重要的优化:您可以从字符计数数组的ASCII / Unicode字符代码中找到该字符的索引。具体来说,字符计数数组中字符c的索引将为c.charCodeAt(0) - 'a'.charCodeAt(0)。这样一来,您就可以在O(1)时间内查找和修改数组中的字符数,从而将算法运行时间缩短至O(n)

答案 1 :(得分:1)

根据您的描述,我假设输入是字符串(在javascript中是不可变的),并且我不确定“一个或两个其他变量” 的确切含义是什么,在您的实现中,我将假设可以使用O(N)空间。为了提高时间复杂度,我认为实现方法会根据输出字符串的不同要求而有所不同。

Assumption1:输出的字符串的顺序与第一次出现的顺序相同。例如。 “ bcabcc”->“ bca”

假设s的长度为N,以下实现使用O(N)空间和O(N)时间。

 function removeDuplicates(s) {
    const set = new Set(); // use set so that insertion and lookup time is o(1)
    let res = "";
    for (let i = 0; i < s.length; i++) {
        if (!set.has(s[i])) {
            set.add(s[i]);
            res += s[i];
        }
    }
    return res;
  }

假设2:输出的字符串必须为升序。

您可以使用快速排序进行就地排序,然后循环遍历已排序的数组以将最后看到的元素添加到结果中。请注意,您可能需要先将字符串拆分为一个数组。因此该实现将使用O(N)空间,平均时间复杂度为O(NlogN)

假设3:在所有可能的结果中,结果按字典顺序排列是最小的。例如。 “ bcabcc”->“ abc”

以下实现使用O(N)空间和O(N)时间。

const removeDuplicates = function(s) {
    const stack = []; // stack and set are in sync
    const set = new Set(); // use set to make lookup faster
    const lastPos = getLastPos(s);
    let curVal;
    let lastOnStack;

    for (let i = 0; i < s.length; i++) {
        curVal = s[i];
        if (!set.has(curVal)) {
            while(stack.length > 0 && stack[stack.length - 1] > curVal && lastPos[stack[stack.length - 1]] > i) {
                set.delete(stack[stack.length - 1]);
                stack.pop();
            }
            set.add(curVal);
            stack.push(curVal);
        }
    }
    return stack.join('');
};

const getLastPos = (s) => {
    // get the last index of each unique character
    const lastPosMap = {};
    for (let i = 0; i < s.length; i++) {
        lastPosMap[s[i]] = i;
    }
    return lastPosMap;
}

答案 2 :(得分:1)

有一个小技巧“不使用任何额外的缓冲区”,尽管我没有找到一种方法来提高beforeEach(() => { fixture = TestBed.createComponent(Component); component = fixture.componentInstance; service = fixture.debugElement.injector.get(Service); }); it('should get a subscription event', () => { const response: any[] = []; service.observer$ = new Subject<any>(); fixture.detectChanges(); service.observer$.next(['some content']); expect(component.x.length).toBeGreaterThan(0); }); 的复杂性,而无需使用散列图来确定是否已看到特定字符。诀窍是遍历输入字符串缓冲区(假定它是一个JavaScript数组,因为JavaScript中的字符串是不可变的),如果当前字符重复,则用下一个唯一字符覆盖当前字符。最后,用空字符标记结果字符串的结尾。

伪代码:

O(n^2)

如果我们使用哈希映射,则函数i = 1 pointer = 1 while string[i]: if not seen(string[i]): string[pointer] = string[i] pointer = pointer + 1 i = i + 1 mark string end at pointer 可能占用seen时间和O(n)空间或O(1)时间和O(1)空间。

答案 3 :(得分:1)

我不确定这是什么意思

  

...不使用任何其他缓冲区。

所以我想我可以一口气做到这一点,让你告诉我是否有错。

我所做的工作是,您提供的功能可以提供正确的输出,而您只是在寻找运行速度更快的功能。下面的函数可以提供正确的输出,并且在处理任何带有大量重复项的大型字符串时,运行速度都快得多。

function removeDuplicates(originalString) {
    let outputString = '';
    let lastChar = '';
    let lastCharOccurences = 1;

    for (let char = 0; char < originalString.length; char++) {
        outputString += originalString[char];

        if (lastChar === originalString[char]) {
            lastCharOccurences++;
            continue;
        }
        
        if (lastCharOccurences > 1) {
            outputString = outputString.slice(0, outputString.length - (lastCharOccurences + 1)) + originalString[char];
            lastCharOccurences = 1;
        }

        lastChar = originalString[char];
    }

    console.log("The string with removed duplicates is:", outputString)
}

removeDuplicates("Hippotamuus")

再次,抱歉,如果我误解了该帖子...