文章目录

  • 一、电话号码的字母组合
    • 回溯 :
  • 二、括号生成
    • 回溯 :
  • 总结
    • 关于回溯和递归
      • 括号生成的递归描述 :
      • 电话号码的字母组合的递归描述 :
    • 括号生成的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:递归和回溯-字符串中的回溯问题相关推荐

  1. leetcode算法题--把数字翻译成字符串

    原题链接:https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/ 相似题目:解码方法 动态规划: dp[i] ...

  2. python【力扣LeetCode算法题库】面试题62- 圆圈中最后剩下的数字(约瑟夫环)

    面试题62. 圆圈中最后剩下的数字 0,1,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字.求出这个圆圈里剩下的最后一个数字. 例如,0.1.2.3.4这5个数字组成一个圆 ...

  3. leetcode算法题--完全平方数★

    原题链接:https://leetcode-cn.com/problems/perfect-squares/ 相关题目:leetcode算法题–零钱兑换 1.回溯法 就是暴力法,套路就是递归,但是有很 ...

  4. LeetCode算法题整理(200题左右)

    目录 前言 一.树(17) 1.1.后序遍历 1.2.层次遍历 1.3.中序 1.4.前序 二.回溯(20) 2.1.普通回溯 2.2.线性回溯:组合.排列.子集.分割 2.3.矩阵回溯 三.二分查找 ...

  5. LeetCode算法题-Factorial Trailing Zeroes(Java实现)

    这是悦乐书的第183次更新,第185篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第42题(顺位题号是172).给定一个整数n,返回n!中的尾随零数.例如: 输入:3 输 ...

  6. LeetCode高频题12:整数转罗马数字

    LeetCode高频题12:整数转罗马数字 提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目 互联网大厂们在公司养了一大批ACM ...

  7. LeetCode算法题-Nth Digit(Java实现)

    这是悦乐书的第215次更新,第228篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第83题(顺位题号是400).找到无限整数序列的第n个数字1,2,3,4,5,6,7,8 ...

  8. LeetCode算法题-Convert a Number to Hexadecimal(Java实现)

    这是悦乐书的第219次更新,第231篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第86题(顺位题号是405).给定一个整数,写一个算法将其转换为十六进制.对于负整数,使 ...

  9. leetcode算法题--不同的二叉搜索树

    原题链接:https://leetcode-cn.com/problems/unique-binary-search-trees/ 相关题目:leetcode算法题--不同的二叉搜索树 II 1.递归 ...

最新文章

  1. oracle不能用uuid,Oracle 应用之--VirtualBox UUID问题
  2. hihoCoder 1367 等式填空
  3. 3-4HDFS的特点
  4. linux 游戏 黑白,黑白迭代官方版游戏-黑白迭代下载v0.5-Linux公社
  5. 聚合数据接口,提供开放API
  6. Mysql在window下的表现_Mysql在windows系统下的配置
  7. 软件工程-团队作业3
  8. 刷屏!马化腾:腾讯只是一家普通公司,随时可以被替换
  9. 使用yolo v3训练自己的模型
  10. 基于STM32的STM8脱机编程器源码分享
  11. yoloV3运行速度测试报告
  12. 论文笔记4 --(ReID)Re-ranking Person Re-identification with k-reciprocal Encoding
  13. 手机语音通讯测试(Mobile Phone Communication Test)
  14. docker run 报错 Bind for 0.0.0.0:80 failed: port is already allocated.解决方案
  15. prisma中where对象转换RedisJson查询字符串
  16. HTML---网页编程(1)
  17. 在线Spirte图定位工具,自动生成CSS
  18. python spearman相关系数_常用的特征选择方法之 Spearman 秩相关系数
  19. Oracle导出导入dmp文件
  20. NRF51822的蓝牙设置

热门文章

  1. 关于渗透的一些思路持续更新(自我理解)
  2. Elasticsearch中如何进行排序(中文+父子文档+嵌套文档)
  3. 第二次 图书助手冲刺第一天
  4. Android 源码VecotorDrawable
  5. 业务系统实现记住密码和自动登录功能
  6. URAL 1152. False Mirrors(DP)
  7. UVa 11520 Fill the Square 填充正方形
  8. context-param和init-param区别
  9. lstm处理时序数据结构图_详解LSTM
  10. hdu4515 小模拟