leetcode 【39,40,216】. Combination Sum I II

博客围绕LeetCode的三道组合求和问题展开,包括39、40和216题。针对各题给出题目描述,均采用深度优先遍历思路解题。如39题可重复选数,40题元素不能重复用,216题从1 - 9选数。还给出不同实现方式及递归返回条件等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.leetcode 39 Combination Sum

题目描述:

Given a set of candidate numbers (candidates(without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [2,3,6,7], target = 7,A solution set is:[[7], [2,2,3]]

Example 2:

Input: candidates = [2,3,5], target = 8,A solution set is:[[2,2,2,2],[2,3,3],[3,5]]

思路:深度优先遍历

1.首先对数组进行排序;

2. 深度优先遍历所有可能解的问题,由于没有设置解集的大小且所有数字都可以重复选取,必须采用能够自动挖掘解集的解法

3. 通过递归的方式对所有可能解集进行遍历。

4.如果加入某个数后导致target-arr[i]小于0,则无需继续遍历,因为数组进行了排序,后面的数比当前数更大,加入后更不会出现为0的结果。这样可以减少一些无用的遍历。

实现1:通用模板解法

一种直观理解的实现方式

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ret=new ArrayList<>();
        Arrays.sort(candidates);
        fun(candidates,target,0,ret,new ArrayList<>());
        return ret; 
    }
    private void fun(int[] arr,int target,int start,List<List<Integer>> ret,ArrayList<Integer> sub){
        if(target<0){
            return;
        }
        if(target==0){
            ret.add(new ArrayList<>(sub));
            return;
        }
        for(int i=start;i<arr.length;i++){
            sub.add(arr[i]);
            fun(arr,target-arr[i],i,ret,sub);
            sub.remove(sub.size()-1);
            if(target<0){
                break;
            }
        }
        return;
    }
}

实现2:

思路和实现1一样,但是不知为何执行时间更快

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ret=new ArrayList<>();
        Arrays.sort(candidates);
        fun(candidates,target,0,ret,new ArrayList<>());
        return ret; 
    }
    private boolean fun(int[] arr, int target, int start, List<List<Integer>> ret, ArrayList<Integer> sub) {
		if(target<0) return false;
		if(target==0){
			ret.add(new ArrayList<>(sub));
			return false;
		}
		for(int i=start;i<arr.length;i++){
			sub.add(arr[i]);
			boolean flag=fun(arr, target-arr[i], i, ret, sub);
			sub.remove(sub.size()-1);
			if(!flag){
				break;
			}
		}
		return true;
	}
}

2. leetcode 40. Combination Sum II

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:[[1, 7],[1, 2, 5],[2, 6],[1, 1, 6]]

Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:[[1,2,2],[5]]

思路:

和上一题一样,需要使用递归,不断的加入尝试,不同的是,这个题中元素不能重复使用,所以在递归的时候是i+1而不是i。

另外,因为数组中有重复的元素,但是组合数同一个数只能算一种,所以需要对这种情况进行过滤。

实现1:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> ret=new ArrayList<>();
        ArrayList<Integer> sub=new ArrayList<>();
        Arrays.sort(candidates);
        fun(candidates,target,0,ret,sub);
        return ret;       
    }
    private boolean fun(int[] arr,int target,int start,List<List<Integer>> ret,ArrayList<Integer> sub){
        if(target<0){
            return false;
        }
        if(target==0){
            ret.add(new ArrayList(sub));
            return false;
        }
        for(int i=start;i<arr.length;i++){
            if(i>start&&arr[i]==arr[i-1]){
                continue;//过滤掉相同的组合
            }
            sub.add(arr[i]);
            boolean flag=fun(arr,target-arr[i],i+1,ret,sub);
            sub.remove(sub.size()-1);
            if(!flag){
                break;
            }   
        }
        return true;       
    }        
}

实现2:通用模板解法

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> ret=new ArrayList<>();
        ArrayList<Integer> sub=new ArrayList<>();
        Arrays.sort(candidates);
        fun(ret,sub,candidates,target,0);
        return ret;
    }
    private void fun(List<List<Integer>> ret,ArrayList<Integer> sub,int[] nums,int target,int start){
        if(target==0){
            ret.add(new ArrayList<>(sub));
            return;
        }
        if(target<0){
            return;
        }
        for(int i=start;i<nums.length;i++){
            if(i>start&&nums[i]==nums[i-1]){
                continue;
            }
            sub.add(nums[i]);
            fun(ret,sub,nums,target-nums[i],i+1);
            sub.remove(sub.size()-1);
            if(target<0){
                break;
            }
        }
        
    }
}

leetcode 216. Combination Sum III

题目描述:

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.

Note:

  • All numbers will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: k = 3, n = 7
Output: [[1,2,4]]

Example 2:

Input: k = 3, n = 9
Output: [[1,2,6], [1,3,5], [2,3,4]]

思路:

仍然是all possible combinations的题目,所以还是用深度搜索算法,和上面的题目解法一样,从1开始向后不断深度搜索满足条件的答案,若不符合,则移除当前值。

递归需要返回的条件:

1.当k==0且n==0,说明我们找到了满足条件的值,此时将该值加入到ret中并return,继续向后搜索。

2.当k==0,但n!=0,或者n<0,此时说明没有找到符合条件的值,也需要返回。

另外,

返回之后我们需要将最后的数移除并不断向后搜索,但是有一种条件下不需要继续向后遍历,那就是n<=i的情况

比如k=3,n=7,我们已经找到满足条件的子数组【1,2,4】,那么就没有必要向后接着遍历了,因为大于4的数加入list中肯定也比7大了。

实现:


class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> ret=new ArrayList<>();
        if(n<0||k>9){
            return ret;
        }
        ArrayList<Integer> sub=new ArrayList<>();
        fun(ret,sub,k,n,1);
        return ret;  
    }
    private void fun(List<List<Integer>> ret,ArrayList<Integer> sub,int k,int n,int start){
        if(k==0&&n==0){
            ret.add(new ArrayList<>(sub));
            return;
        }
        if(k==0&&n!=0||n<0){
            return;
        }
        for(int i=start;i<=9;i++){
       
            sub.add(i);
            fun(ret,sub,k-1,n-i,i+1);
            sub.remove(sub.size()-1);
            if(n<=i){
                break;
            }
        }
    }
}

 

参考:

https://www.jianshu.com/p/42211be17acb

https://blog.youkuaiyun.com/obrcnh/article/details/78820889

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值