• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
xiaoyaovo
博客园    首页    新随笔    联系   管理    订阅  订阅
【LeetCode 40】 组合问题II(Java)

题目

  • 链接:

组合问题II

  • 题目描述:

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。candidates 中的每个数字在每个组合中只能使用一次。
注意:解集不能包含重复的组合。

  • 输入

candidates = [10,1,2,7,6,1,5]
target = 8

  • 输出

[[1,1,6],[1,2,5],[1,7],[2,6]]

思路

这道题就三个要求

  1. 在数组中找出和为 target的组合;
  2. 数组中每个数字只能用一次;
  3. 结果集合不能重复,也就是要去重。

刚开始的思路

  1. dfs + 回溯 + 剪大枝 求结果集合;

回溯:每个数字只能用一次,所有要回溯,虽然有重复的数字。
剪大枝:如果当前结果已经超出了 target,而数组是有序的,那么就说明后面的也超出了 target。这里 剪大枝 也只是为了优化。

  1. 去重。
class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<Integer> list = new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();

        // dfs搜索 + 回溯
        Arrays.sort(candidates);
        res = dfs(candidates,target,0,list,res);

        // 去重
        int i = 0;
        while (i < res.size()) {
            boolean success = false;
            for (int j = i + 1; j < res.size(); j++) {
                if (isSame(res.get(i), res.get(j))) {
                    res.remove(j);
                    success = true;
                }
            }
            if (success) {
                if (i > 1) {
                    i--;
                }else {
                    i = 0;
                }
            }else {
                i++;
            }
        }

        // 结果
        return res;
    }

    /**
    搜索 
     */
    public  List<List<Integer>> dfs(int[] candidates,int target,int index,List<Integer> list, List<List<Integer>> res) {
        if (target == 0) {
            res.add(new ArrayList<>(list));
            return res;
        }
        for (int i = index; i < candidates.length;i++) {
        	// 剪大枝
            if (target < 0) {
                break;
            }
            list.add(candidates[i]);
            dfs(candidates,target-candidates[i],i+1,list,res);
			
			// 回溯 因为每个数字只能用一次
            list.remove(list.size()-1);
        }
        return res;
    }

    /**
    去重
     */
    public boolean isSame(List<Integer> list1, List<Integer> list2) {
        int i = 0,j = 0;
        while (i < list1.size() && j < list2.size()) {
            if (list1.get(i) != list2.get(j)) {
                return false;
            }
            i++;
            j++;
        }
        return i == list1.size() && j == list2.size();
    }
}

然后就超时了,确实时间复杂度挺高的。 于是看了一下解析,大佬们都是再在 递归 的时候去重的,也就是所谓的 剪枝,但是这里是 剪小枝。

代码

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<Integer> list = new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();

        // dfs搜索 + 回溯
        Arrays.sort(candidates);
        res = dfs(candidates,target,0,list,res);

        // 结果
        return res;
    }

    /**
    搜索 
     */
    public  List<List<Integer>> dfs(int[] candidates,int target,int index,List<Integer> list, List<List<Integer>> res) {
        if (target == 0) {
            res.add(new ArrayList<>(list));
            return res;
        }
        for (int i = index; i < candidates.length;i++) {

            // 剪大枝(优化)
            if (target < 0) {
                break;
            }
            
            // 剪小枝(去重)
            if (i > index && candidates[i] == candidates[i-1]) {
                continue;
            }

            list.add(candidates[i]);
            dfs(candidates,target-candidates[i],i+1,list,res);

            // 回溯
            list.remove(list.size()-1);
        }
        return res;
    }

示例

  • 测试用例

int[] candidates = {1,2,2,2,5};
int target = 5.

  • 解释

递归:
target = 5
target = 5 - 1 = 4
target = 4 - 2 = 2
target = 2 - 2 = 0
==>res.add(new ArrayList<>(list)
==> 回溯:
==>list.remove(list.size()-1).
target = 2
i == 3 > index == 2 && candidates[3] == candidates[2] == 2
==> continue;
此时就达到了去重的目的。

posted on 2021-08-02 18:31  豆本豆红枣豆奶  阅读(9)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3