回溯
🌸题目
🍁给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
🌸分析
对于打印"2345"这样的字符串:
第一次递归就是上图中最下面的方格,然后处理完第一个字符2之后,将输入的字符改变成"345"并调用第二个递归函数
第二次递归处理3,将字符串改变成"45"后再次递归
第三次递归处理4,将字符串改变成"5"后继续递归
第四次递归处理5,将字符串改变成""后继续递归
最后发现字符串为空了,将结果放到列表中并返回
上面是从函数调用的角度去看的,而每次调用下一层递归时,都需要将本层的一些处理结果放到一个临时变量中,再传递给下一层,从这个变量层层传递的变化看,就像一棵树一样,这个算法的时间复杂度很高,是O(3^n)这个级别的,空间复杂度是O(n)
🌸解法一:回溯
class Solution {//一个映射表,第二个位置是"abc“,第三个位置是"def"。。。//这里也可以用map,用数组可以更节省点内存String[] letter_map = {" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};public List<String> letterCombinations(String digits) {//注意边界条件if(digits==null || digits.length()==0) {return new ArrayList<>();}iterStr(digits, "", 0);return res;}//最终输出结果的listList<String> res = new ArrayList<>();//递归函数void iterStr(String str, String letter, int index) {//递归的终止条件,注意这里的终止条件看上去跟动态演示图有些不同,主要是做了点优化//动态图中是每次截取字符串的一部分,"234",变成"23",再变成"3",最后变成"",这样性能不佳//而用index记录每次遍历到字符串的位置,这样性能更好if(index == str.length()) {res.add(letter);return;}//获取index位置的字符,假设输入的字符是"234"//第一次递归时index为0所以c=2,第二次index为1所以c=3,第三次c=4//subString每次都会生成新的字符串,而index则是取当前的一个字符,所以效率更高一点char c = str.charAt(index);//map_string的下表是从0开始一直到9, c-'0'就可以取到相对的数组下标位置//比如c=2时候,2-'0',获取下标为2,letter_map[2]就是"abc"int pos = c - '0';String map_string = letter_map[pos];//遍历字符串,比如第一次得到的是2,页就是遍历"abc"for(int i=0;i<map_string.length();i++) {//调用下一层递归,用文字很难描述,请配合动态图理解iterStr(str, letter+map_string.charAt(i), index+1);}}
}
# python
class Solution(object):def letterCombinations(self, digits):""":type digits: str:rtype: List[str]"""# 注意边界条件if not digits:return []# 一个映射表,第二个位置是"abc“,第三个位置是"def"。。。# 这里也可以用map,用数组可以更节省点内存d = [" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]# 最终输出结果的listres = []# 递归函数def dfs(tmp,index):# 递归的终止条件,注意这里的终止条件看上去跟动态演示图有些不同,主要是做了点优化# 动态图中是每次截取字符串的一部分,"234",变成"23",再变成"3",最后变成"",这样性能不佳# 而用index记录每次遍历到字符串的位置,这样性能更好if index==len(digits):res.append(tmp)return# 获取index位置的字符,假设输入的字符是"234"# 第一次递归时index为0所以c=2,第二次index为1所以c=3,第三次c=4# subString每次都会生成新的字符串,而index则是取当前的一个字符,所以效率更高一点c = digits[index]# map_string的下表是从0开始一直到9, ord(c)-48 是获取c的ASCII码然后-48,48是0的ASCII# 比如c=2时候,2-'0',获取下标为2,letter_map[2]就是"abc"letters = d[ord(c)-48]# 遍历字符串,比如第一次得到的是2,页就是遍历"abc"for i in letters:# 调用下一层递归,用文字很难描述,请配合动态图理解dfs(tmp+i,index+1)dfs("",0)return res
🌸解法二:暴力法(队列)
class Solution {public List<String> letterCombinations(String digits) {if(digits==null || digits.length()==0) {return new ArrayList<String>();}//一个映射表,第二个位置是"abc“,第三个位置是"def"。。。//这里也可以用map,用数组可以更节省点内存String[] letter_map = {" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};List<String> res = new ArrayList<>();//先往队列中加入一个空字符res.add("");for(int i=0;i<digits.length();i++) {//由当前遍历到的字符,取字典表中查找对应的字符串String letters = letter_map[digits.charAt(i)-'0'];int size = res.size();//计算出队列长度后,将队列中的每个元素挨个拿出来for(int j=0;j<size;j++) {//每次都从队列中拿出第一个元素String tmp = res.remove(0);//然后跟"def"这样的字符串拼接,并再次放到队列中for(int k=0;k<letters.length();k++) {res.add(tmp+letters.charAt(k));}}}return res;}
}
class Solution(object):def letterCombinations(self, digits):""":type digits: str:rtype: List[str]""" if not digits:return []# 一个映射表,第二个位置是"abc“,第三个位置是"def"。。。# 这里也可以用map,用数组可以更节省点内存d = [" ","*","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]# 先往队列中加入一个空字符res = [""]for i in digits:size = len(res)# 由当前遍历到的字符,取字典表中查找对应的字符串letters = d[ord(i)-48]# 计算出队列长度后,将队列中的每个元素挨个拿出来for _ in xrange(size):# 每次都从队列中拿出第一个元素tmp = res.pop(0)# 然后跟"def"这样的字符串拼接,并再次放到队列中for j in letters:res.append(tmp+j)return res
最后,不经历风雨,怎能在计算机的大山之顶看见彩虹呢! 无论怎样,相信明天一定会更好!!!!!
发布者:admin,转转请注明出处:http://www.yc00.com/news/1708430033a1562477.html
评论列表(0条)