代码随想录算法训练营第二十五天|216.组合总和III、17.电话号码的字母组合

目录

216.组合总和III

17.电话号码的字母组合


216.组合总和III

如果把 组合问题理解了,本题就容易一些了。

题目链接/文章讲解:代码随想录

视频讲解:和组合问题有啥区别?回溯算法如何剪枝?| LeetCode:216.组合总和III_哔哩哔哩_bilibili

题解思路:

本题和77题思路类似,主要是熟悉回溯算法的模板写法,然后就是本题存在的两个剪枝情况,可以减少搜索的时间,具体的剪枝操作如下(代码中有详细注释):
剪纸操作一:如果添加的元素和大于目标之和时,及时return结束本次递归,进行下一次递归操作即可;
剪枝操作二,控制要达到k个个数时,最多还需要遍历到哪里结束即可,具体操作为9 - (k - path.size()) + 1!!!

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> result = new ArrayList<>();
    int sum = 0;

    public List<List<Integer>> combinationSum3(int k, int n) {
        backtracking(k,n,1);
        return result;
    }

    public void backtracking(int k, int n, int startIndex){
        if(sum > n) return ; //剪纸操作一:如果添加的元素和大于目标之和时,及时return结束本次递归,进行下一次递归操作即可
        if(path.size() == k ){
            if(sum == n){
                result.add(new LinkedList(path));
                return;
            }
        }
        for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++ ){ //9 - (k - path.size()) + 1:这里是剪枝操作二,控制要达到k个个数时,最多还需要遍历到哪里结束即可
            path.add(i); //往path路径中及时添加元素
            sum += i; //添加的元素及时相加操作
            backtracking(k, n, i + 1); //不断的朝着深度方向进行搜索,直到遇到return结束方法的语句才算完成一次递归,紧接着进行回溯操作
            path.removeLast(); //递归遇到return后及时减去刚添加的元素,回溯到第一次递归的状态
            sum -= i; //递归遇到return后及时减去刚添加的元素,回溯到前一次递归的状态
        }
    }
}

17.电话号码的字母组合

本题大家刚开始做会有点难度,先自己思考20min,没思路就直接看题解。

题目链接/文章讲解:代码随想录

视频讲解:还得用回溯算法!| LeetCode:17.电话号码的字母组合_哔哩哔哩_bilibili

题解思路:

本题还是得有卡哥指路的,否则不会这么容易想到这么全面的解法,主要是先第一步:先把数字键盘通过数组下标映射成字符串,然后取字符串里面的字母组合,然后画出对应的树形结构进行一步一步分析,因为我第一次写这道题就是完全不知道从哪里下手,看到题目直接懵逼了,根据树形的求解思路再找出里面的关系就好。

class Solution {
    String[] mapLetter = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; //第一步:先把数字键盘通过数组下标映射成字符串,然后取字符串里面的字母组合
    LinkedList<String> path = new LinkedList<>();
    List<String> result = new ArrayList<>();
    StringBuilder temp = new StringBuilder(); //大量的字符串拼接可以选择更为高效的StringBuilder

    public List<String> letterCombinations(String digits) {
        if(digits == null || digits.length() == 0) return result; //这个剪枝操作是真恶心,还是需要直接判断如果digits == [""]或者不存在时时,直接return结果集即可
        bancktracking(digits,0);
        return result;
    }

    public void bancktracking(String digits, int index){ //index变量指向的是给定的数字字符串中的下标索引值,由于结果集中的大小和数字字符串大小一致,所以可以用过索引值控制回溯算法的终止条件,如下所示
        if(index == digits.length()){ //index从0开始索引给定的数字字符,通过index的索引值控制递归的终止条件,只有当满足终止条件时,才进行结果的处理
            result.add(temp.toString());
            return;
        }
        
        String letter = mapLetter[digits.charAt(index) - '0']; //digits[index]:获取给定数字字符串指定索引值的数字字符,从0开始获取的;digits[index] - '0':获取对应数字字符的int的数,传入到映射数组中,再获取数字字符对应的字符串!!!
        //这里要注意踩坑,一定是digits[index] - '0':表示两个字符串进行相加操作,得到的是int类型结果,'2'- '0' == 2,而不是digits[index] - 0:表示吧'2'先转换成ASCII码,其数值为50,再与0进行相减操作;
        for(int i = 0; i < letter.length(); i++){
            temp.append(letter.charAt(i));
            bancktracking(digits, index + 1);
            temp.deleteCharAt(temp.length() - 1);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/tore007/article/details/130671627