代码随想录第二十二天| 77. 组合 216.组合总和III 17.电话号码的字母组合

题目:组合

问题描述:给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。

解题思路

  1. 回溯法:使用回溯法生成所有可能的组合。
  2. 递归构建组合
  • 从1到n中选择一个数作为组合的第一个数,然后递归地从剩余的数中选择k-1个数。
  1. 剪枝优化
  • 在递归过程中,通过计算剩余可选的数的数量来提前终止不必要的递归,从而减少计算量。
  1. 路径记录
  • 使用一个列表 path 来记录当前的组合路径。
  1. 结果收集
  • path 的长度等于 k 时,将其添加到结果列表 result 中。

代码:

class Solution {
	List<List<Integer>> result = new ArrayList<>();
	LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtreeing(n,k,1);
		return result;
    }
	public void backtreeing(int n, int k,int startindex) {
		if(path.size() == k){
			result.add(new ArrayList<>(path));
			return;
		}
		for(int i = startindex;i<=n;i++){
			path.add(i);
			backtreeing(n,k,i+1);
			path.removeLast();
		}
	}
}
class Solution {
	List<List<Integer>> result = new ArrayList<>();
	LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> combine(int n, int k) {
        backtreeing(n,k,1);
		return result;
    }
	public void backtreeing(int n, int k,int startindex) {
		if(path.size() == k){
			result.add(new ArrayList<>(path));
			return;
		}
		for(int i = startindex;i<=n-(k-path.size())+1;i++){
			path.add(i);
			backtreeing(n,k,i+1);
			path.removeLast();
		}
	}
}

216. 组合总和 III

题目描述

找出所有相加之和为 nk 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

  • 所有数字都是正整数。
  • 解集不能包含重复的组合。

解题思路

这道题是一个典型的回溯问题。我们需要从数字 1 到 9 中选择 k 个数字,并确保它们的和为 n。通过回溯的方式,我们可以探索所有的组合。

关键点:

  1. 递归回溯:每次选择一个数字,并将其添加到路径中,再继续选择下一个数字。回溯时要恢复状态。
  2. 限制条件
    • 当前组合的大小不能超过 k
    • 每次选择的数字不能重复,并且必须从当前位置的下一个数字开始选择。
    • 如果当前路径的和为 n 且路径大小为 k,则记录该路径。

步骤:

  1. 递归调用:我们从 1 开始递归,每次选择一个数字加入路径并继续递归。
  2. 回溯:当递归到一个路径大小为 k 时,检查路径和是否为 n。如果是,加入结果列表。
  3. 优化剪枝:为了避免不必要的递归,递归中的 startIndex 会根据剩余的数字个数进行调整。具体来说,在每一层递归中,我们可以减少剩余选择的数字数量。

代码实现

class Solution {
	private List<List<Integer>> result = new ArrayList<>();
	private LinkedList<Integer> path = new LinkedList<Integer>();
    public List<List<Integer>> combinationSum3(int k, int n) {
		treebuild(k,n,0,1);
		return result;
    }
	public void treebuild(int k, int n,int sum,int startindex) {
		if(path.size()==k){
			if(sum==n){
				result.add(new ArrayList<>(path));
			}
			return;
		}
		for(int i=startindex;i<10;i++){
			path.add(i);
			sum=sum+i;
			treebuild(k,n,sum,i+1);
			sum=sum-i;
			path.removeLast();
		}
	}
}
class Solution {
	private List<List<Integer>> result = new ArrayList<>();
	private LinkedList<Integer> path = new LinkedList<Integer>();
    public List<List<Integer>> combinationSum3(int k, int n) {
		treebuild(k,n,0,1);
		return result;
    }
	public void treebuild(int k, int n,int sum,int startindex) {
		if(path.size()==k){
			if(sum==n){
				result.add(new ArrayList<>(path));
			}
			return;
		}
		for(int i=startindex;i<10-(k-path.size())+1;i++){
			path.add(i);
			sum=sum+i;
			treebuild(k,n,sum,i+1);
			sum=sum-i;
			path.removeLast();
		}
	}
}

17. 电话号码的字母组合

题目描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母

解题思路

这道题是一个典型的回溯问题。我们需要通过递归遍历每个数字对应的字母,然后生成所有可能的字母组合。

关键点:

  1. 数字到字母的映射:每个数字(2-9)都对应一组字母,我们可以用数组或者字典来存储这种映射。
  2. 回溯法:我们可以使用回溯法来生成所有可能的组合。每次递归时,选择当前数字对应的字母之一,然后进入下一个数字的递归调用。
  3. 字符串拼接:用 StringBuilder 来拼接每次的选择,避免频繁创建新的字符串。
  4. 终止条件:当递归到达数字字符串的末尾时,表示一个完整的组合已经生成,将其添加到结果列表中。

步骤:

  1. 递归遍历:从数字字符串的第一个字符开始,遍历所有可能的字母,递归调用下一层。
  2. 回溯:每当递归进入下一层时,我们会选择一个字母,递归回来后,删除上次选择的字母,继续选择下一个字母。

代码实现

class Solution {
	private String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
	List<String> list = new ArrayList<>();
	StringBuilder path = new StringBuilder();
    public List<String> letterCombinations(String digits) {
		if(digits==null || digits.length()==0){
			return list;
		}
		treebuilding(digits,0);
		return list;
    }
	public void treebuilding(String digits,int startindex) {
		if(startindex==digits.length()){
			list.add(path.toString());
			return;
		}
		String str = numString[digits.charAt(startindex)-'0'];
		for(int i = 0;i<str.length();i++){
			path.append(str.charAt(i));
			treebuilding(digits,startindex+1);
			path.deleteCharAt(path.length()-1);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值