组合问题

1. 选取 k 个数
在这里插入图片描述
回溯法:以选取的个数作为条件跳出

class Solution {

    public static void backtracking(List<Integer> combineList, List<List<Integer>> combinations, int start, int k, int n) {
	    if (k == 0) {
	        combinations.add(new ArrayList<>(combineList));
	        return;
	    }
	    for (int i = start; i <= n - k + 1; i++) {  // 剪枝
	        combineList.add(i);
	        backtracking(combineList, combinations, i + 1, k - 1, n);
	        combineList.remove(combineList.size() - 1);
	    }
	}
    
    public List<List<Integer>> combine(int n, int k) {
        List<List<Integer>> combinations = new ArrayList<>();
	    List<Integer> combineList = new ArrayList<>();
	    backtracking(combineList, combinations, 1, k, n);
	    return combinations;
    }
}

2. 选取固定和 target,数字可以重复选取但解集不含重复组合
在这里插入图片描述
在这里插入图片描述
回溯法:以和为条件跳出

class Solution {

    public static void dfs(int[] candidates,int target,List<Integer> perm,int index,List<List<Integer>> res) {
		if(target==0) {
			res.add(new ArrayList<Integer>(perm));
			return;
		}
		for(int i=index;i<candidates.length;i++) {
			if(target>=candidates[i]) {
				perm.add(candidates[i]);
				dfs(candidates,target-candidates[i],perm,i,res);
				perm.remove(perm.size()-1);
			}
		}
	}

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
		List<List<Integer>> res=new ArrayList<List<Integer>>();
		List<Integer> perm=new ArrayList<Integer>();
		dfs(candidates,target,perm,0,res);
		return res;
    }
}

3. 选取固定和 target,数字不可以重复选取且解集不含重复组合
在这里插入图片描述
在这里插入图片描述
注意去重

class Solution {

    public static void backtracking(List<Integer> tempCombination, List<List<Integer>> combinations,
			boolean[] hasVisited, int start, int target, final int[] candidates) {

		if (target == 0) {
			combinations.add(new ArrayList<>(tempCombination));
			return;
		}
		for (int i = start; i < candidates.length; i++) {
			// 第一次进入函数时i=0的时候不会执行到i-1
			if (i != 0 && candidates[i] == candidates[i - 1] && !hasVisited[i - 1]) {   // 去重的关键
				continue;
			}
			if (candidates[i] <= target) {
				tempCombination.add(candidates[i]);
				hasVisited[i] = true;
				backtracking(tempCombination, combinations, hasVisited, i + 1, target - candidates[i], candidates);
				hasVisited[i] = false;
				tempCombination.remove(tempCombination.size() - 1);
			}else {
				return;
			}
		}
	}

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> combinations = new ArrayList<>();
	    Arrays.sort(candidates);
	    backtracking(new ArrayList<>(), combinations, new boolean[candidates.length], 0, target, candidates);
	    return combinations;
    }
}

4. 同时要求固定和 target 和选取个数 k
在这里插入图片描述
回溯法:同时将两个条件用作跳出判断

class Solution {

    public static void dfs(List<Integer> perm,int k,int n,int index,List<List<Integer>> res) {
		if(n==0 && k==0) {
			res.add(new ArrayList<Integer>(perm));
			return;
		}
		if(index<=n) {
			for(int st=index;st<=9;st++) {
				perm.add(st);
				dfs(perm,k-1,n-st,st+1,res);
				perm.remove(perm.size()-1);
			}
		}
	}
    
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> res=new ArrayList<List<Integer>>();
		if(n<1 || k==0) {
			return res;
		}
		dfs(new ArrayList<Integer>(),k,n,1,res);
		return res;
    }
}

5. 选取固定和 target,数字可以重复选取且解集可包含重复的组合(顺序不同)
在这里插入图片描述
在这里插入图片描述
动态规划:

class Solution {
    public int combinationSum4(int[] nums, int target) {
        int[] dp = new int[target + 1];
        dp[0] = 1;
        for (int i = 1; i <= target; i++) {
            for (int num : nums) {
                if (i >= num) {
                    dp[i] += dp[i - num];
                }
            }
        }
        return dp[target];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值