zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/yrbbest/p/4436333.html
Copyright © 2011-2022 走看看