【LeetCode选讲·第六期】「整数/罗马数字互转」「最长公共前缀」「电话号码的字母组合」

767 阅读2分钟

T12 整数转罗马数字

题目链接:leetcode-cn.com/problems/in…

本题的关键在于能够从题目给的示例中发掘出转换过程中应当尽量使用大数的罗马数字符号这一隐含的贪心策略,且能认识到所有特殊转换规则只需一一罗列即可,之后这题就变成了一道简单的模拟题。

代码如下:

function intToRoman(num) {
    let hash = new Map([ [1000, 'M'], [900, 'CM'], [500, 'D'],
        [400, 'CD'], [100, 'C'], [90, 'XC'],
        [50, 'L'], [40, 'XL'], [10, 'X'],
        [9, 'IX'], [5, 'V'], [4, 'IV'], [1, 'I']
    ]);
    let ans = '';
    hash.forEach((val, key) => {
        while(num >= key) {
            num -= key;
            ans += val;
        }
    });
    return ans;
}

除此之外,我还在LeetCode上看到有网友直接提取输入数据的各十百千位分别进行转换。在精神高度紧张、时间受限的情况下,这也不失为一种应试策略。

T13 罗马数字转整数

题目链接:leetcode-cn.com/problems/ro…

这题是T12的逆过程,但相比之下难度更低,只需要利用哈希表对传入的字符一一对照即可。

代码如下:

function romanToInt(str) {
    let hash = new Map([ ['M', 1000], ['CM', 900], ['D', 500],
        ['CD', 400], ['C', 100], ['XC', 90],
        ['L', 50], ['XL', 40], ['X', 10],
        ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]
    ]);
    let ans = 0;
    let i = 0
    while (i < str.length) {
        //优先尝试两位字符
        if (hash.has(str[i] + str[i + 1])) {
            ans += hash.get(str[i] + str[i+1]);
            i += 2;
        }
        //处理普通的一位字符
        else if (hash.has(str[i])) {
            ans += hash.get(str[i]);
            i++;
        }
    }
    return ans;
}

T14 最长公共前缀

题目链接:leetcode-cn.com/problems/lo…

朴素解法

我们可以直接对传入的各字符串进行逐位比较。过一遍代码:

function longestCommonPrefix(strs) {
    let ans = '';
    let str0 = strs[0];
    let tempS = '';
    for(let i = 0; i < str0.length; i++) {
        tempS = str0[i];
        for(let j = 1; j < strs.length; j++) {
            if(strs[j][i] !== tempS) return ans;
        }
        ans += tempS;
    }
    //如果第一个字符串恰好是最长子串,则遍历结束后直接返回结果
    return ans;
}

拓展:字典序排序

分析上面的朴素解法,我们会发现其缺陷也很明显,即我们在检查过程中不得不遍历strs中的所有字符串逐个检查,这时我们便可以考虑采用字典序排序,即根据字符串逐位ASCII码的大小进行排序,来避免这一过程。

(tip:JavaScript等语言中对字符串进行大小比较时也使用了字典序排序的规则)

当我们对strs进行字典序排序后,根据其规则可以推知一个重要结论:差异最大的两个字符串势必会被排序至数组的最两侧。 因而我们只需要比较数组中位于最前端和最尾端的两个字符串即可!

更幸运的是,JavaScript中的Array.prototype.sort内置了字典序排序的功能,我们可以直接运用TA来改造我们上面的代码,而不必自己手工实现排序算法。

改造后的代码如下:

function longestCommonPrefix(strs) {
    strs.sort();
    let ans = '';
    let str0 = strs[0];
    let str1 = strs[strs.length - 1];
    let tempS = '';
    for(let i = 0; i < str0.length; i++) {
        tempS = str0[i];
        if (str1[i] !== tempS) return ans;
        ans += tempS;
    }
    return ans;
}

通过此题我们可以发现,JavaScript中一些原生方法的功能是十分强大的,在日常开发过程中,我们必然首推使用它们进行代码编写。但在算法学习的过程中,我们却不可过分依赖它们,以免久而久之弱化自己的编程能力。在应试时,更应注意是否存在禁止(或暗示禁止)使用某些原生方法的特殊要求,以免造成不必要的损失。

T17 电话号码的字母组合

题目链接:leetcode-cn.com/problems/le…

这是一道简单的DFS入门题,难度低于我早前在掘金上分享的「八皇后问题」「John的篮球」。

这里我们直接过一遍代码:

const Hash = {
    '2': ["a", "b", "c"],
    '3': ["d", "e", "f"],
    '4': ["g", "h", "i"],
    '5': ["j", "k", "l"],
    '6': ["m", "n", "o"],
    '7': ["p", "q", "r", "s"],
    '8': ["t", "u", "v"],
    '9': ["w", "x", "y", "z"],
};
function letterCombinations(digits) {
    let ans = [];
    digits.length > 0 && dfs(digits, '', ans);
    return ans;
}
function dfs(restDigits, curStr, ans) {
    let curDig = restDigits[0];
    if(curDig !== void 0) {
        for(let s of Hash[curDig]) {
            dfs(restDigits.slice(1), curStr + s, ans);
        }
    } else {
        ans.push(curStr);
    }
}

写在文末

我是来自在校学生编程兴趣小组江南游戏开发社的PAK向日葵,我们目前正在致力于开发自研的非营利性网页端同人游戏《植物大战僵尸:旅行》,以实战锻炼我们的前端应用开发能力。

我们诚挚邀请您体验我们的这款优秀作品,如果您喜欢TA的话,欢迎向您的同事和朋友推荐。如果您有技术方面的问题希望与我们探讨,欢迎直接与我联系。您的支持是我们最大的动力!

QQ图片20220701165008.png