性能提升?indexOf 为什么比 for 快 20 倍?是否接近 O(1) 的复杂度?

5,888 阅读2分钟

前言

该文章并不能给你一个很好的解答,只能提出一些猜想,因为我并没有好的机器语言基础,也没有看过 JS 源码。

问题来源

问题的来源是一道 leetcode 的题目的两次提交记录。

而这两次提交记录的唯一代码区别就是将一个 for 替换为了 indexOf

image.png

题目

给定一个字符串数组 words,找到 length(word[i]) * length(word[j]) 的最大值,并且这两个单词不含有公共字母。你可以认为每个单词只包含小写字母。如果不存在这样的两个单词,返回 0。

示例 1:

输入: ["abcw","baz","foo","bar","xtfn","abcdef"]
输出: 16 
解释: 这两个单词为 "abcw", "xtfn"

示例 2:

输入: ["a","ab","abc","d","cd","bcd","abcd"]
输出: 4 
解释: 这两个单词为 "ab", "cd"

示例 3:

输入: ["a","aa","aaa","aaaa"]
输出: 0 
解释: 不存在这样的两个单词。

提交代码

未使用 indeOf

var maxProduct = function (words) {
    const hasPublic = (x, y) => {
        for (let i = 0; i < x.length; i++) {
            for (let j = 0; j < y.length; j++) {
                if (x[i] === y[j]) return true
            }
        }
        return false
    }

    let max = 0
    // let b = ''
    for (let i = 0; i < words.length; i++) {
        const e = words[i]
        for (let j = i; j < words.length; j++) {
            const ee = words[j]
            if (!hasPublic(e, ee)) {
                const m = e.length * ee.length
                max = max > m ? max : m
            }
        }
    }
    return max
};

使用 indexOf


var maxProduct = function (words) {
    const hasPublic = (x, y) => {
        for (let i = 0; i < x.length; i++) {
            if (y.indexOf(x[i]) > -1) {
                return true
            }
        }
        return false
    }

    let max = 0
    for (let i = 0; i < words.length; i++) {
        const e = words[i]
        for (let j = i; j < words.length; j++) {
            const ee = words[j]
            if (!hasPublic(e, ee)) {
                const m = e.length * ee.length
                max = max > m ? max : m
            }
        }
    }
    return max
};

一些猜想

在这两次截然不同的执行时间得到后,我曾猜想 indexOf 的执行效率无限接近于 O(1)

猜想原因1

由于 JS 内部实现 indexOf 不是使用 JS 实现的,而是用 C 等较低级别的语言编写的,从而提供了更高的性能。

猜想原因2

JS 内部可能对于 indexOf 这种字符串方法未采用循环的方式获取,极有可能采用 原、反、补 的方式实现,但由于大学的内容未时常复习,不太能想起来如何实现,故不知是否可行。

stackOverflow 获取到的一些信息

由于内网没有查到类似的内容,故在 stackOverflow 进行搜索,这里供大家查看。

indexOf 不会在恒定时间内运行

测试用例:

// create a very long string aaaa...ab...bc...cd (etc)
let alpha = "abcdefghijklmnopqrstuvwxyz";
let s = Array.from(alpha, c => c.repeat(10000000)).join("");
// find each of the letters in this long string
for (let c of alpha) {
    let start = performance.now();
    s.indexOf(c);
    let end = performance.now();
    console.log(end-start);
}

最后

如果我有幸找到了问题的答案,我会回来补充这篇文章。

如果您知道答案,或者有其他猜想,请务必在评论区留下您的 答案、猜想 。万分感谢。

最后,祝大家共同成长!