「这是我参与11月更文挑战的9天,活动详情查看:2021最后一次更文挑战」。
前言
一直都计划学习数据结构与基本算法,但是平时都看一阵停一阵。现在决心坚持下去,我准备从LeetCode的HOT100开始,每天完成1~2道习题,希望通过这种方式养成持续学习的习惯。因为我是做iOS开发的,主要是用Objective-C语言,最近也在学习Swift,所以本系列的题解都将使用swift语言完成,本文更新的是LeetCode中HOT100的第9题017 电话号码的字母组合。
题目
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = ""
输出:[]
示例 3:
输入:digits = "2"
输出:["a","b","c"]
提示:
0 <= digits.length <= 4
digits[i] 是范围 ['2', '9'] 的一个数字。
分析
本题的目标是求所有字符的全排列组合,而且也给出了每一个数组对应的字符集,所以当题目中出现 “所有组合” 等类似字眼时,我们第一感觉就要想到用回溯。
下图是输入'23'时对应的输出结果,我们发现其实这有点类似树的结构,我们要做的就是对这棵树做深度优先算法进行遍历,找出所有长度为2(即输入字符串长度)路径组合。
所以本题采用深度优先算法(DFS)进行,基本思路如下:
1. 初始化当前下标curIndex = 0,当前组合子串为空串subStr = ""
2. 如果当前下标curIndex没有超出数字串digits的范围,则获取curIndex对应数字的字符集curMatch;
否则表示深度已经最大,将subStr添加到结果集,over
3. 将curMatch中的第一个元素元素添加到subStr中,添加元素后递归步骤2,调用时将curIndex后移一位,递归调用步骤2后将subStr中的最后一个元素删除,添加curMatch中的下一个元素
题解
class KLLC017 {
func letterCombinations(_ digits: String) -> [String] {
if digits.count == 0 {
return [String]()
}
// 建立字符和字符匹配数组的关联
let matches = [
"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"]
];
//初始化 curIndex curSubStr
var result = [String]()
var curSubStr = ""
let curIndex = digits.startIndex
//dfs调用,从第一个字符开始
dfs(&curSubStr, digits, curIndex, matches, &result)
return result
}
//dfs算法
func dfs(_ curSubStr:inout String, _ digits:String, _ curIndex:String.Index, _ matches:Dictionary<String, [String]>, _ result:inout [String]){
//如果当前下标超出字符范围,则over,保存结果
if curIndex == digits.endIndex {
let subStr = curSubStr
result.append(subStr)
return
}
//没有超出范围则继续,获取当前下标对应的 数字 以及 数字对应的匹配字符数组
let curDigit = String(digits[curIndex])
let curMatch = matches[curDigit] ?? [String]()
// 依次将匹配字符加入curSubStr
for ch in curMatch {
//将当前字符加入curSubStr
curSubStr.append(ch)
//递归调用,进行下一位的处理
dfs(&curSubStr, digits, digits.index(after: curIndex), matches, &result)
//从curSubStr中移除最后一位,即移除刚刚添加的匹配字符,为当前数字对应的下一匹配字符加入curSubStr,同一个数字对应的匹配字符只能添加一次
curSubStr.removeLast()
}
}
}