LeetCode算法题12:递归和回溯-字符串中的回溯问题
文章目录
- 一、电话号码的字母组合
- 回溯 :
- 二、括号生成
- 回溯 :
- 总结
- 关于回溯和递归
- 括号生成的递归描述 :
- 电话号码的字母组合的递归描述 :
- 括号生成的BFS描述 :
一、电话号码的字母组合
题目链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
题目描述:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
回溯 :
思路,本题为组合问题,从 n 个集合中每次选取一个字符构成一个新的字符串,然后列出所有的这些字符串。那就每次从某一个集合中依次取出一个字符,回溯时删除该字符即可。采用回溯算法常用的框架即可。
参考代码如下(带注释):
public List<String> letterCombinations(String digits) {char[] cc=new char[26];for(int i=0;i<26;i++)cc[i]=(char)(i+'a');//cc 保存26个小写字符int len=digits.length();List<String> re=new ArrayList<>();//返回得到的结果。if(len==0)return re;List<char[]> getIn=new ArrayList<>(len);//将 digits 中的字符转换为对应的字符数组存储起来。for(int i=0;i<len;i++){char tmp=digits.charAt(i);if(tmp<'2'||tmp>'9')continue;if(tmp>='2'&&tmp<'7'){int from=(int)(tmp-'0')-2;getIn.add(Arrays.copyOfRange(cc,from*3,from*3+3));}else if(tmp=='7')getIn.add(new char[]{'p','q','r','s'});else if(tmp=='8')getIn.add(new char[]{'t','u','v'});elsegetIn.add(new char[]{'w','x','y','z'});}solve(getIn,getIn.size(),re,new char[getIn.size()],0);return re;}//参数 size:一共有多少个集合可供选择,tmp:一个存储组合结果的字符数组,count:记录tmp中已经选定的字符数,也标记当前正在哪一个集合中选取字符。public void solve(List<char[]> getIn,int size,List<String> re,char[] tmp,int count){if(count==size){//此时得到了一个合格的组合结果,保存起来。re.add(new String(tmp));return;}int len=getIn.get(count).length;//每次递归选取由count对应的哪个集合。for(int i=0;i<len;i++){tmp[count]=getIn.get(count)[i];solve(getIn,size,re,tmp,count+1);//在下一个集合中选取字符。//无须多余的回退到上一个状态的代码,在此采用的是字符数组,直接覆盖即可。}}
上面程序的执行顺序:从最后一个集合依次选取每一个字符,在从倒数第二个集合开始选取…直到第一个集合。然后程序结束。对输入的处理自己采用了字符数组(代码看着有些复杂),当然也可以采用别的方式。
关于处理输入:用map也可以,但是懒的敲那么字符。比如这样:
String[] input = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
或者这样:
Map<Character, String> phoneMap = new HashMap<Character, String>();phoneMap.put('2', "abc");phoneMap.put('3', "def");phoneMap.put('4', "ghi");phoneMap.put('5', "jkl");phoneMap.put('6', "mno");phoneMap.put('7', "pqrs");phoneMap.put('8', "tuv");phoneMap.put('9', "wxyz");
二、括号生成
题目链接:https://leetcode-cn.com/problems/generate-parentheses/
题目描述:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
回溯 :
思路,本题的难点个人觉得应该是在约束条件的处理上,即左右括号一定要对应,特别的:每次在添加右括号之前必须有一个相对应的左括号存在。用栈也可以,但最简单的方法是统计左右括号的个数。左括号可以随意添加,只要其个数不要超过n就好;右括号添加时特别要注意必须有一个左括号和它对应。
参考代码如下(带注释):
public List<String> generateParenthesis(int n) {int left=0,right=0;//初始时均为0,表示一个组合中已有的左右括号的个数。每次可以添加一个右括号的前提是left必须大于rightList<String> re=new ArrayList<>();StringBuilder tmp=new StringBuilder();//用来保存一个可能的组合solve(re,n,left,right,tmp);return re;}public void solve(List<String> re,int n,int left,int right,StringBuilder tmp){if(right==n){//结束条件为添加最后一个右括号时re.add(new String(tmp));return;}if(left<n){tmp.append('(');solve(re,n,left+1,right,tmp);//对下一个位置的元素做选择tmp.deleteCharAt(tmp.length()-1);//回退}if(left>right){tmp.append(')');solve(re,n,left,right+1,tmp);tmp.deleteCharAt(tmp.length()-1);}}
上面这个解法和官方题解思路完全一致哈。
总结
关于回溯和递归
括号生成的递归描述 :
递归解法,依照约束条件来分类递归。它和回溯的区别仅在于它不需要回退,解决问题的思想基本一致,都是采用了深度优先遍历的方式。参考代码如下:
public List<String> generateParenthesis(int n) {int left=0,right=0;//初始时均为0,表示一个组合中已有的左右括号的个数。每次可以添加一个右括号的前提是left必须大于rightList<String> re=new ArrayList<>();solve(re,n,left,right,"");return re;}public void solve(List<String> re,int n,int left,int right,String tmp){if(right==n){//结束条件为添加最后一个右括号时。re.add(tmp);return;}if(left<n)solve(re,n,left+1,right,tmp+"(");if(left>right)solve(re,n,left,right+1,tmp+')');}
电话号码的字母组合的递归描述 :
很简单的,就可以将本题的回溯代码转换为递归实现,如下:
public List<String> letterCombinations(String digits) {char[] cc=new char[26];for(int i=0;i<26;i++)cc[i]=(char)(i+'a');//cc 保存26个小写字符int len=digits.length();List<String> re=new ArrayList<>();//返回得到的结果。if(len==0)return re;List<char[]> getIn=new ArrayList<>(len);//将 digits 中的字符转换为对应的字符数组存储起来。for(int i=0;i<len;i++){char tmp=digits.charAt(i);if(tmp<'2'||tmp>'9')continue;if(tmp>='2'&&tmp<'7'){int from=(int)(tmp-'0')-2;getIn.add(Arrays.copyOfRange(cc,from*3,from*3+3));}else if(tmp=='7')getIn.add(new char[]{'p','q','r','s'});else if(tmp=='8')getIn.add(new char[]{'t','u','v'});elsegetIn.add(new char[]{'w','x','y','z'});}solve(getIn,getIn.size(),re,"",0);return re;}public void solve(List<char[]> getIn,int size,List<String> re,String tmp,int count){if(count==size){re.add(tmp);return;}int len=getIn.get(count).length;for(int i=0;i<len;i++)solve(getIn,size,re,tmp+getIn.get(count)[i],count+1);}
在 leetcode 中测试之后可以发现,递归解法的效率要低于回溯,可能是因为需要不断地创建字符串吧。
括号生成的BFS描述 :
采用 BFS 的解法需要保存每一种中间结点的 left 和 right 值,在递归(DFS)中不需要,因为它们是由系统栈进行存储的。参考代码如下:
//BFS//需要新建一个结点类,因为每个结点需要保存自己的 left 和 right 值。private static class Node{String value;int left,right;//初始时均为0,表示一个组合中已有的左右括号的个数。每次可以添加一个右括号的前提是left必须大于rightpublic Node(){value="";left=right=0;};public Node(String s,int le,int ri){value=s;left=le;right=ri;};}public List<String> generateParenthesis(int n) {LinkedList<Node> re=new LinkedList<>();re.add(new Node());Node tmp;while(!re.isEmpty()){tmp=re.poll();if(tmp.left<n)re.add(new Node(tmp.value+"(",tmp.left+1,tmp.right));if(tmp.left>tmp.right)re.add(new Node(tmp.value+")",tmp.left,tmp.right+1));if(re.peek().value.length()==2*n)break;}List<String> ans=new ArrayList<>();for(Node node:re)ans.add(node.value);return ans;}
LeetCode算法题12:递归和回溯-字符串中的回溯问题相关推荐
- leetcode算法题--把数字翻译成字符串
原题链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/ 相似题目:解码方法 动态规划: dp[i] ...
- python【力扣LeetCode算法题库】面试题62- 圆圈中最后剩下的数字(约瑟夫环)
面试题62. 圆圈中最后剩下的数字 0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 例如,0.1.2.3.4这5个数字组成一个圆 ...
- leetcode算法题--完全平方数★
原题链接:https://leetcode-cn.com/problems/perfect-squares/ 相关题目:leetcode算法题–零钱兑换 1.回溯法 就是暴力法,套路就是递归,但是有很 ...
- LeetCode算法题整理(200题左右)
目录 前言 一.树(17) 1.1.后序遍历 1.2.层次遍历 1.3.中序 1.4.前序 二.回溯(20) 2.1.普通回溯 2.2.线性回溯:组合.排列.子集.分割 2.3.矩阵回溯 三.二分查找 ...
- LeetCode算法题-Factorial Trailing Zeroes(Java实现)
这是悦乐书的第183次更新,第185篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第42题(顺位题号是172).给定一个整数n,返回n!中的尾随零数.例如: 输入:3 输 ...
- LeetCode高频题12:整数转罗马数字
LeetCode高频题12:整数转罗马数字 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目 互联网大厂们在公司养了一大批ACM ...
- LeetCode算法题-Nth Digit(Java实现)
这是悦乐书的第215次更新,第228篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第83题(顺位题号是400).找到无限整数序列的第n个数字1,2,3,4,5,6,7,8 ...
- LeetCode算法题-Convert a Number to Hexadecimal(Java实现)
这是悦乐书的第219次更新,第231篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第86题(顺位题号是405).给定一个整数,写一个算法将其转换为十六进制.对于负整数,使 ...
- leetcode算法题--不同的二叉搜索树
原题链接:https://leetcode-cn.com/problems/unique-binary-search-trees/ 相关题目:leetcode算法题--不同的二叉搜索树 II 1.递归 ...
最新文章
- oracle不能用uuid,Oracle 应用之--VirtualBox UUID问题
- hihoCoder 1367 等式填空
- 3-4HDFS的特点
- linux 游戏 黑白,黑白迭代官方版游戏-黑白迭代下载v0.5-Linux公社
- 聚合数据接口,提供开放API
- Mysql在window下的表现_Mysql在windows系统下的配置
- 软件工程-团队作业3
- 刷屏!马化腾:腾讯只是一家普通公司,随时可以被替换
- 使用yolo v3训练自己的模型
- 基于STM32的STM8脱机编程器源码分享
- yoloV3运行速度测试报告
- 论文笔记4 --(ReID)Re-ranking Person Re-identification with k-reciprocal Encoding
- 手机语音通讯测试(Mobile Phone Communication Test)
- docker run 报错 Bind for 0.0.0.0:80 failed: port is already allocated.解决方案
- prisma中where对象转换RedisJson查询字符串
- HTML---网页编程(1)
- 在线Spirte图定位工具,自动生成CSS
- python spearman相关系数_常用的特征选择方法之 Spearman 秩相关系数
- Oracle导出导入dmp文件
- NRF51822的蓝牙设置