• 40. Combination Sum II


    题目:

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

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

    Note:

    • All numbers (including target) will be positive integers.
    • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
    • The solution set must not contain duplicate combinations.

    For example, given candidate set 10,1,2,7,6,1,5 and target 8
    A solution set is: 
    [1, 7] 
    [1, 2, 5] 
    [2, 6] 
    [1, 1, 6] 

    链接: http://leetcode.com/problems/combination-sum-ii/

    题解:

    依然是一道DFS + Backtracking题目。 与之前不同的是每个数字只允许使用一次。所以在回溯的循环里当 i > pos时,假如之后又重复的,continue。我们依然使用candidates[i],而且candidates[i + 1]假如等于candidates[i], 会在DFS的下一个阶段被使用到。当然假如不用这个巧妙的条件也可以, 可以在 target == 0的时候判断res中是否contains  list,这样的话运行速度会慢不少,但也可以AC.

    Time Complexity - O(), Space Complexity - O()。 如何计算复杂度,智商捉急啊...

    public class Solution {
        public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            List<List<Integer>> res = new ArrayList<>();
            if(candidates == null || candidates.length == 0)
                return res;
            Arrays.sort(candidates);
            ArrayList<Integer> list = new ArrayList<>();
            dfs(res, list, candidates, target, 0);
            return res;
        }
        
        private void dfs(List<List<Integer>> res, ArrayList<Integer> list, int[] candidates, int target, int pos) {
            if(target == 0) {
                res.add(new ArrayList<Integer>(list));
                return;
            }
            if(pos >= candidates.length || target < 0)
                return;
            
            for(int i = pos; i < candidates.length; i++) {
                if(i > pos && candidates[i] == candidates[i - 1])           //for i > pos, if duplicate,continue. we still use candidates[i]
                    continue;
                list.add(candidates[i]);
                dfs(res, list, candidates, target - candidates[i], i + 1);
                list.remove(list.size() - 1);
            }
        }
    }

    二刷:

    这里依然是用了跟上一题目很接近的方法。不同的地方在于,每个数字不可以被无限次。所以一个数只能一次,而且遇到重复数字我们要跳过。这样我们在for循环里要加入一条 -  if (i > pos && candidates[i] == candidates[i - 1]) continue; 并且在DFS的时候每次

    每次新的position = i + 1, 并不是上一题的position = i。

    看到有discuss里有方法用array来做backtracking,速度beat 99%,以后也可以把list改成array,试一试这种方法。

    Java:

    public class Solution {
        public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            List<List<Integer>> res = new ArrayList<>();
            if (candidates == null || candidates.length == 0) {
                return res;
            }
            Arrays.sort(candidates);
            List<Integer> comb = new ArrayList<>();
            combinationSum2(res, comb, candidates, target, 0);
            return res;
        }
        
        private void combinationSum2(List<List<Integer>> res, List<Integer> comb, int[] candidates, int target, int pos) {
            if (target < 0) {
                return;
            } else if (target == 0) {
                res.add(new ArrayList<>(comb));
            }
            for (int i = pos; i < candidates.length; i++) {
                if (i > pos && candidates[i] == candidates[i - 1]) {
                    continue;
                }
                int num = candidates[i];
                if (num > target) {
                    return;
                }
                comb.add(num);
                combinationSum2(res, comb, candidates, target - num, i + 1);
                comb.remove(comb.size() - 1);
            }
        }
    }

    三刷:

    跟上题唯一不同就是递归时把控制position的变量从 i 变成了 i + 1,这样我们就不会对一个元素进行多次计算。

    Java:

    public class Solution {
        public List<List<Integer>> combinationSum2(int[] candidates, int target) {
            List<List<Integer>> res = new ArrayList<>();
            if (candidates == null) return res;
            Arrays.sort(candidates);
            findCombinations(res, new ArrayList<>(), candidates, target, 0);
            return res;
        }
        
        private void findCombinations(List<List<Integer>> res, List<Integer> list, int[] candidates, int target, int pos) {
            if (target < 0) return;
            if (target == 0) {
                res.add(new ArrayList<>(list));
                return;
            }
            for (int i = pos; i < candidates.length; i++) {
                if (candidates[i] > target) break;
                if (i > pos && candidates[i] == candidates[i - 1]) continue;
                list.add(candidates[i]);
                findCombinations(res, list, candidates, target - candidates[i], i + 1);
                list.remove(list.size() - 1);
            }
        }
    }

    Reference:

    https://leetcode.com/submissions/detail/51501884/

  • 相关阅读:
    [leetcode] First Missing Positive
    [leetcode] Can Place Flowers
    [leetcode] Maximum Product of Three Numbers
    [leetcode] Generate Parentheses
    蓝桥杯 PREV-7 连号区间数
    蓝桥杯 PREV-3 带分数(dfs)
    蓝桥杯 PREV-2 打印十字图
    团体程序设计天梯赛 L3-016 二叉搜索树的结构 (30分)
    团体程序设计天梯赛 L3-020 至多删三个字符 (30分)(DP)
    团体程序设计天梯赛 L3-011 直捣黄龙 (30分)
  • 原文地址:https://www.cnblogs.com/yrbbest/p/4436333.html
Copyright © 2020-2023  润新知