算法(附思维导图+全部解法)300题之17电话号码的字母组合
零 标题:算法(leetode,附思维导图 + 全部解法)300题之(17)电话号码的字母组合
导读:
一 题目描述
二 解法总览(思维导图)
三 全部解法
1 方案1
1)代码:
// 方案1 回溯(说白了、说穿了,就是递归。因为一般用递归实现回溯)。 // 技巧:永远记住,递归 = 递归出口(为了不陷入无线递归的死循环) + 递归主体(一般会变更一些参数后,在调用函数本身)。 // 一般 递归出口 放前面,递归主体 放后面。 var letterCombinations = function(digits) { // 1)定义回溯函数(即递归函数dfs)。 const dfs = (index, l, digits, curStr, resArr) => { // 1.1)递归出口 if (index >= l) { resArr.push(curStr); return; } // 1.2)递归主体 const tempArr = map.get(digits[index]), tempLength = tempArr.length; // 核心:回溯 = 选 + 不选。 // 该for循环表示穷举每种可能,然后 选tempArr[i] ,不选其他。 for (let i = 0; i < tempLength; i++) { dfs(index + 1, l, digits, curStr + tempArr[i], resArr); } }; // 2)状态初始化。 const l = digits.length, map = new Map([ ['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']] ]); let index = 0, curStr = '', resArr = []; // 3)调用自定义的回溯函数(即递归函数dfs)。 // 3.1)边界:"" ,预期为 []。 // 若不加 该if分支, 则自己的将输出为 [""]。 if (l <= 0) { return []; } dfs(index, l, digits, curStr, resArr); // 4)返回结果 resArr 。 return resArr; };
2 方案2
1)代码:
// 方案2 将digits字符串转二维数组;不断遍历做笛卡尔积;返回最终的“笛卡尔积数组”。 // 技巧:涉及“映射、数量、重复性、唯一性(即次数)等”可优先考虑hash(JS里对应的是 map数据结构)。 // 1)"234" 转成 [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'] ] // 2)核心:遍历该二维数组,不断跟下一个元素做笛卡尔积。 // 2.1)初始化:newAcc = ['a', 'b', 'c'] // 2.2)当前newAcc 与下一个元素['d', 'e', 'f'] 做笛卡尔积, // 得到 newAcc = ["ad","ae","af","bd","be","bf","cd","ce","cf"] // 2.3)重复2.2步骤,做笛卡尔积。 // 得到 newAcc = ["adg","adh","adi","aeg","aeh","aei","afg","afh","afi","bdg","bdh","bdi","beg","beh","bei","bfg","bfh","bfi","cdg","cdh","cdi","ceg","ceh","cei","cfg","cfh","cfi"] // 3)遍历结束,返回 newAcc 。 var letterCombinations = function(digits) { // 1)状态初始化。 const l = digits.length, map = new Map([ ['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']] ]); // 2)将原先的 digits字符串 转成 相应的二维数组tempArr。 // 如 "234" 转成 [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'] ]。 const tempArr = digits.split('').map(item => { return map.get(item); }); let newAcc = []; // 3)将上面转换得到的二维数组tempArr 变成 一维数组resArr 。 // 技巧:多变一,优先考虑使用 数组的reduce方法 。 const resArr = tempArr.reduce((acc, cur, index, item) => { // 边界:若是第一个元素,直接返回 item[index] 。 if (index === 0) { newAcc = item[index]; return newAcc; } const accLength = acc.length, curLength = cur.length; // 边界:需重置 newAcc 为 [] , // 继续 用当前的acc、cur 拼接出 newAcc 。 newAcc = []; // 3.1)核心:遍历 acc、cur ,拼接出 newAcc 。 for (let i = 0; i < accLength; i++) { for (let j = 0; j < curLength; j++) { newAcc.push(acc[i] + cur[j]); } } // 3.2)返回由 acc、cur 拼接出的 newAcc 。 return newAcc; }, []); // 4)返回结果 resArr 。 return resArr; }
3 方案3
1)代码:
// 方案3 与方案2类似,只是不使用 reduce 函数了。 // 也是不断遍历做笛卡尔积;返回最终的“笛卡尔积数组”。 // 技巧:涉及“映射、数量、重复性、唯一性(即次数)等”可优先考虑hash(JS里对应的是 map数据结构)。 // 1)"234" 转成 [ ['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'] ] // 2)核心:遍历该二维数组,不断跟下一个元素做笛卡尔积。 // 2.1)初始化:resArr = ['a', 'b', 'c'] // 2.2)当前resArr 与下一个元素['d', 'e', 'f'] 做笛卡尔积, // 得到 resArr = ["ad","ae","af","bd","be","bf","cd","ce","cf"] // 2.3)重复2.2步骤,做笛卡尔积。 // 得到 resArr = ["adg","adh","adi","aeg","aeh","aei","afg","afh","afi","bdg","bdh","bdi","beg","beh","bei","bfg","bfh","bfi","cdg","cdh","cdi","ceg","ceh","cei","cfg","cfh","cfi"] // 3)遍历结束,返回 resArr 。 var letterCombinations = function(digits) { // 1)状态初始化。 const l = digits.length, map = new Map([ ['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']] ]); let resArr = []; // 边界:若长度为 0 ,则 直接返回[] 。 if (l === 0) { // 其实就是 return []; return resArr; } else { // 若长度 不为 0 ,则 初始化 resArr 为 map.get(digits[0]); 。 resArr = map.get(digits[0]); } // 2)遍历。 // 核心:不断做笛卡尔积、更新 resArr 值。 // 注:下标从1(因为之前已经 resArr = map.get(digits[0]); )开始! for (let i = 1; i < l; i++) { const tempArr = map.get(digits[i]), tempArrLength = tempArr.length, resArrLength = resArr.length; let newResArr = []; for (let j = 0; j < resArrLength; j++) { for (let k = 0; k < tempArrLength; k++) { newResArr.push(resArr[j] + tempArr[k]); } } resArr = newResArr; } // 3)返回结果 resArr 。 return resArr; }#面经##学习路径#