当前位置: 首页 > news >正文

电话号码的字母组合组合总和II 回溯注意事项(Java)

电话号码的字母组合

思路:多个循环可以考虑回溯。

首先明确:

  1. 循环的宽度是多少,即从哪些区间取数(本题目中每个数字都是3个字母,都是从三个字母中取一个数,所以可以确定循环宽度就是每个数字对应的字符串的长度)
  2. 循环的高度是多少,即循环终止条件(分别从每个数字里取一个字母,所以循环高度就是给出的数字的数量)
  3. 循环的区间是什么,用什么可以统一表达并递归(字母的联系是数字,需要找出每层循环中的循环数字,那就使用Index取数字)
  4. 是否需要剪枝:如果求sum问题可以提前剪枝,本题目不用
class Solution {
    List<String> res = new ArrayList<>();
    List<String> sub = new ArrayList<>();
    StringBuffer sb = new StringBuffer();
    Map<Character, String> map = new HashMap<>(); //Character用的好
    int n = 3;
    public List<String> letterCombinations(String digits) {
        int len = digits.length(); //几层--循环宽度
        if(len == 0){
            return res;
        }
        map.put('2', "abc"); //找出对应关系
        map.put('3', "def");
        map.put('4', "ghi");
        map.put('5', "jkl");
        map.put('6', "mno");
        map.put('7', "pqrs");
        map.put('8', "tuv");
        map.put('9', "wxyz");
        fucLetter(digits, len, 0);
        return res;
    }
    public void fucLetter(String digits, int len, int Index){
        if(sb.length() == len){
            res.add(sb.toString());
            return;
        }
        char c = digits.charAt(Index); //找到每个数字
        String s = map.get(c); // 取出对应字符串
        for(int i = 0; i < s.length(); i++){ //循环字符串
            sb.append(s.charAt(i));
            fucLetter(digits, len, Index + 1);
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

组合总和

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> sub = new ArrayList<>();
    int target;
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        this.target = target;
        Arrays.sort(candidates); // 剪枝的话先进行排序
        fucSum(candidates, 0, 0);
        return res;
    }
    public void fucSum(int[] candidates, int sum, int startIndex){
        if(sum > target){
            return;
        }
        if(sum == target){
            res.add(new ArrayList<>(sub));
            return;
        }
        for(int i = startIndex; i < candidates.length; i++){ //从startIndex开始
            if(sum + candidates[i] > target){
                break; //这个不要return,直接break
            } //这个剪枝注意一下
            sub.add(candidates[i]);
            sum += candidates[i];
            
            fucSum(candidates, sum, i); //允许可以重复,从当前元素即可!
            sub.remove(sub.size() - 1);
            sum -= candidates[i];
            
        }
    }
}

组合总和II

  1. 思路1:去除重复的集合,但是if(i != 0 && candidates[i] == candidates[i - 1])单纯这样写是不够的,因为这样也把纵向重复去除了(纵向重复并不会导致集合重复)!!!区分纵向和横向的关系:纵向是递归,横向是回溯,只有return后才是回溯,所以还是需要一个标注代表是同一层还是同一纵,用boolean use[] = new boolean[candidates.length]来记录,正常纵向递归时标注为true,回溯时变为false。
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> sub = new ArrayList<>();
    boolean use[];
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        use = new boolean[candidates.length]; //默认为false
        Arrays.sort(candidates); // 剪枝前先进行排序
        fucCombine(candidates, target, 0, 0);
        return res;
        
    }
    public void fucCombine(int[] candidates, int target, int startIndex, int sum){
        if(sum > target){
            return;
        }
        if(sum == target){
            res.add(new ArrayList<>(sub));
            return;
        }
        for(int i = startIndex; i < candidates.length; i++){
            if(i != 0 && candidates[i] == candidates[i - 1] && use[i - 1] == false){ //单纯这样写是不够的,因为这样也把纵向重复去除了!区分纵向和横向的关系:纵向是递归,横向是回溯,只有return后才是回溯
                continue;
            }
            if(candidates[i] + sum > target){
                break;
            }
            use[i] = true;
            sub.add(candidates[i]);
            sum += candidates[i];
            fucCombine(candidates, target, i + 1, sum);
            sub.remove(sub.size() - 1);
            sum -= candidates[i];
            use[i] = false;
        }
    }
}
  1. 思路2:使用if(i > startIndex && candidates[i] == candidates[i - 1])去重!!天才!!ifi > startIndex说明是同一层的for循环!!直接去重
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> sub = new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    
        Arrays.sort(candidates); // 剪枝前先进行排序
        fucCombine(candidates, target, 0, 0);
        return res;
        
    }
    public void fucCombine(int[] candidates, int target, int startIndex, int sum){
        if(sum > target){
            return;
        }
        if(sum == target){
            res.add(new ArrayList<>(sub));
            return;
        }
        for(int i = startIndex; i < candidates.length; i++){
            if(i > startIndex && candidates[i] == candidates[i - 1]){
                continue;
            }
            if(candidates[i] + sum > target){
                break;
            }
         
            sub.add(candidates[i]);
            sum += candidates[i];
            fucCombine(candidates, target, i + 1, sum);
            sub.remove(sub.size() - 1);
            sum -= candidates[i];
       
        }
    }
}

回溯注意事项

  1. 何时定义startIndex,即循环从startIndex开始,例如: for(int i = startIndex; i < candidates.length; i++) ?当每一层要循环的区间有关联时,不允许跟之前重复,此时循环从startIndex开始。
  2. 递归时startIndex的值如何赋予?如果要求一个元素只能出现一次
    ,那么使用i+1,即:fucSum(candidates, sum, i+1); 否则使用i,即:fucSum(candidates, sum, i)
  3. 剪枝优化

写博客的目的是每日督促并记录刷题,也欢迎大家批评指正~(day25)

相关文章:

  • AI玩具迎来爆发式增长,IoT行业如何抓住机遇?
  • Linux 目录结构(文件系统结构)示例说明
  • Python第六章15:字典(dict)定义
  • XCode中使用MonkeyDev开发iOS版的Comand-line Tool的daemon程序
  • IntelliJ IDEA(2024版) 的安装、配置与使用教程:常用配置、创建工程等操作(很详细,你想要的都在这里)
  • Redis 和 MySQL双写一致性的更新策略有哪些?常见面试题深度解答。
  • vue3 vite mock实践
  • 使用 Docker 18 安装 Eureka:解决新版本 Docker 不支持的问题
  • Spring Boot 实现定时任务的案例
  • 使用django的DRF业务逻辑应该放在序列化器类还是模型类
  • pyqt第一个窗口程序
  • 黑马点评项目
  • Maven声明周期
  • 第4.1节:使用正则表达式
  • Jira讲解
  • wgcloud怎么实现服务器或者主机的远程关机、重启操作吗
  • 树莓派超全系列文档--(10)RaspberryOS上使用 Python
  • mysql dump某一张表
  • 3. 实战(一):Spring AI Trae ,助力开发微信小程序
  • nara wpe去混响学习笔记
  • 房产资讯/seo项目经理
  • android开发者官网/深圳网站设计专家乐云seo
  • 武汉网站建设找哪家/软文代写价格
  • 网络视频网站建设多少钱/可以免费投放广告的平台
  • 广州网站建设乛新科送推广/新闻株洲最新
  • 人力资源网站建设/广东seo推广外包