代码之家  ›  专栏  ›  技术社区  ›  metrallador10

哪种代码更好?效率与代码可读性

  •  0
  • metrallador10  · 技术社区  · 2 年前

    我用不同的方法解决了一个问题。我想知道哪种方法更好。

    我相信就时间复杂性而言,第一种方法更有效,但代码很长,看起来很乱,但它对循环少用了1。 第二种方法使用3 for循环,但代码看起来要干净得多。 我想问你,你认为哪种代码更好,比如我们应该优先考虑高效但混乱的代码,还是效率较低但更容易阅读的代码。

    这是问题陈述:

    给定一个字符串单词数组,返回可以在美国键盘的一行上使用字母表中的字母键入的单词,如下图所示。

    在美式键盘中:

    第一行由字符“qwertyuiop”组成, 第二行由字符“asdfghjkl”组成,以及 第三行由字符“zxcvbnm”组成。

    第一种方法(混乱但高效):

    var findWords = function(words) {
        const first_row = "qwertyuiop";
        const second_row = "asdfghjkl";
        const third_row = "zxcvbnm";
        let row = "first";
        let accepted_words = [];
    
        words.forEach((word) => {
            for (var i = 0; i < word.length; i++) {
                if (i === 0) {
                    if (first_row.includes(word[i].toLowerCase())) {
                        if (i === word.length - 1) accepted_words.push(word);
                        row = "first";
                    } else if (second_row.includes(word[i].toLowerCase())) {
                        if (i === word.length - 1) accepted_words.push(word);
                        row = "second";
                    } else if (third_row.includes(word[i].toLowerCase())) {
                        if (i === word.length - 1) accepted_words.push(word);
                        row = "third";
                    } else {
                        break;
                    }
                } else {
                    if (first_row.includes(word[i].toLowerCase()) && row === "first") {
                        if (i === word.length - 1) accepted_words.push(word);
                    } else if (second_row.includes(word[i].toLowerCase()) && row === "second") {
                        if (i === word.length - 1) accepted_words.push(word);
                    } else if (third_row.includes(word[i].toLowerCase()) && row === "third") {
                        if (i === word.length - 1) accepted_words.push(word);
                    } else {
                        break
                    }
                }
            }
        });
    
        return accepted_words;
    }
    

    第二种方法(效率较低):

    var findWords = function(words) {
        const rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
        let accepted_words = [];
    
        words.forEach((word) => {
            for (row of rows) {
                for (var i = 0; i < word.length; i++) {
                    if (row.includes(word[i].toLowerCase())) {
                            if (i === word.length - 1) {
                                accepted_words.push(word);
                            }
                    } else {
                        break
                    }
                }
            }
        });
    
        return accepted_words;
    }
    
    1 回复  |  直到 2 年前
        1
  •  1
  •   Bergi    2 年前

    实际上,您的第一个片段并不高效。当然,它有一个 for 更少,但它有6个 if s.只是 unrolling the loop ,这是可能的,因为它在固定大小的数组上循环。它具有持续的复杂性( O(1) )在两种解决方案中。

    要使速度更快,请在接受单词后跳过其他行,并使用一些高阶函数使其更具可读性:

    const rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
    function findWords(words) {
        return words.filter(word => {
            return rows.some(row => {
                return word.split('').every(letter => {
                    return row.includes(letter.toLowerCase());
                });
            });
        });
    }
    

    为了使其更快,即使是巨大的字母表(不仅仅是26个英文字母)和同样巨大的键盘(有很多大行,不仅仅是3个),也要避免在 rows 并在里面的字母上循环 row (与 includes ).将键盘布局预处理为查找映射:

    const rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
    const rowByLetter = new Map(rows.flatMap(row =>
        row.split('').map(letter => [letter, row])
    ));
    function findWords(words) {
        return words.filter(word => {
            if (word.length <= 1) return true;
            const row = rowByLetter.get(word[0].toLowerCase());
            return word.slice(1).split('').every(letter =>
                row === rowByLetter.get(letter.toLowerCase())
            );
        });
    }
    
        2
  •  1
  •   James    2 年前

    如果你不介意先做一些工作,你可以分两个循环来做-在这种情况下,创建一个对象,将每个字母与它出现的行链接起来。然后,当需要分析一些单词时,你可以将该对象用作快速O(1)引用。

    const rows = ["qwertyuiop", "asdfghjkl", "zxcvbnm"];
    
    const rowLookup = rows.reduce((look, row, rowindex) => {
      row.split("").forEach((letter) => {
        look[letter] = rowindex;
      });
      return look;
    }, {});
    
    //console.log(rowLookup);
    
    var findWords = function(words) {
      return words.filter(word => {
        let [firstLetter, ...letters] = word.toLowerCase().split("");
        return letters.every(l => rowLookup[l] === rowLookup[firstLetter]);
      });
    };
    
    let x = "This is a typewriter".split(" ");
    
    console.log(findWords(x));