LeetCode 39 组合总数 LeetCode 40 组合总数2 一起

组合总数

39. 组合总和

  给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
  candidates 中的数字可以无限制重复被选取

思路

首先经典的,看到组合数类似的,采用回溯的思想,详情看代码注释

代码

import java.util.*;

public class combinationSum {
/**
     * @return java.util.List<java.util.List<java.lang.Integer>>
     * @author chy
     * @creed: Talk is cheap,show me the code
     * @date 9/4/2019 3:10 PM
     * @desc: 39. 组合总和
     * 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
     * <p>
     * candidates 中的数字可以无限制重复被选取。
     */
    public List<List<Integer>> combinationSum(int[] candidates, int target) {

        LinkedHashSet<ArrayList<Integer>> re = new LinkedHashSet<ArrayList<Integer>>();//首先,新建一个二维的列表用来存放结果,且使用set来对结果进行去重
        Arrays.sort(candidates);//对候选词进行排序可以减少重复
//        dfs(candidates, target, new ArrayList<>(), re, 0);
        dfs(candidates, target, new ArrayList<>(), 0, re, 0);//进入递归
        List<List<Integer>> list = new ArrayList<>();
        for (ArrayList item : re) {
            list.add(new ArrayList<>(item));
        }
        return list;
    }

    /*
     *
      * @return void
     * @author chy
     * @creed: Talk is cheap,show me the code
     * @date 10/4/2019 2:50 PM
     * @desc:
     * 参数说明: cans为候选数字列表,target为当前递归层的目标,temp为存放候选结果序列,re为存放结果的二维列表,num为当前所指向的候选中的下标
     */
    public void dfs(int[] cans, int target, List<Integer> temp, LinkedHashSet<ArrayList<Integer>> re, int num) {
        if (target == 0) {//递归结束条件,dfs到达叶节点
            re.add(new ArrayList<>(temp));//这里注意需要新建一个列表对象将temp包裹进去,因为这边不是基础类型,为引用传递
            return;
        } else {
            //还没有到达叶子节点时,对当前层的节点进行遍历,分别判断便进入相应子树
            for (int i = num; i < cans.length; i++) {
                //当当前层的结点值小于等于目标时,说明还需要进入子节点
                if ( cans[i] <= target) {
                    //递归需要注意,对于当前层状态的保留,在从当前层进去,再从子树中回退回来时,当前层的一些变量需要还原
                    temp.add(cans[i]);
                    Integer t = cans[i];
                  //  cans[i] = -1;
                    dfs(cans, target - t, temp, re, i);
                //    cans[i] = t;
                    temp.remove(temp.size() - 1);
                }
            }

        }

    }
    //这是未简化的版本
    public void dfs(int[] cans, int target, List<Integer> temp, int tempSum, LinkedHashSet<ArrayList<Integer>> re, int num) {
        for (int i = num; i < cans.length; i++) {
            if (cans[i] == -1)
                continue;
            if (cans[i] + tempSum == target) {
                temp.add(cans[i]);
                re.add(new ArrayList<>(temp));
                if (temp.size() > 0)
                    temp.remove(temp.size() - 1);
            } else if (tempSum + cans[i] > target) {
                if (temp.size() > 0)
                    temp.remove(temp.size() - 1);
                break;
            } else {
                List<Integer> tt = new ArrayList<>(temp);
                tt.add(cans[i]);
                int t = cans[i];
                cans[i] = -1;
                dfs(cans, target, tt, tempSum + t, re, i);
                cans[i] = t;

            }
        }


    }

    public static void main(String argc[]) {
        List<List<Integer>> re = new combinationSum().combinationSum(new int[]{10, 1, 2, 7, 6, 1, 5}, 8);
        for (List<Integer> item : re) {
            for (Integer i : item)
                System.out.print(i);
            System.out.println("");
        }
    }
}


组合总数2

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

思路

和像一条相同,使用回溯法,但是有一个区别,此题对于候选数组中的元素只能使用一次,上面一条可以重复,因此此题需要做一个限制,当候选列表中的某一个候选元素被使用后,需要将其标记一下,下次扫到直接略过。

代码

import java.util.*;

public class combinationSum {
    /**
     * @return java.util.List<java.util.List<java.lang.Integer>>
     * @author chy
     * @creed: Talk is cheap,show me the code
     * @date 9/4/2019 3:10 PM
     * @desc: 39. 组合总和
     * 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
     * <p>
     * candidates 中的数字可以无限制重复被选取。
     */
    public List<List<Integer>> combinationSum(int[] candidates, int target) {

        LinkedHashSet<ArrayList<Integer>> re = new LinkedHashSet<ArrayList<Integer>>();//首先,新建一个二维的列表用来存放结果,且使用set来对结果进行去重
        Arrays.sort(candidates);//对候选词进行排序可以减少重复
//        dfs(candidates, target, new ArrayList<>(), re, 0);
        dfs(candidates, target, new ArrayList<>(), 0, re, 0);//进入递归
        List<List<Integer>> list = new ArrayList<>();
        for (ArrayList item : re) {
            list.add(new ArrayList<>(item));
        }
        return list;
    }

    /*
     *
      * @return void
     * @author chy
     * @creed: Talk is cheap,show me the code
     * @date 10/4/2019 2:50 PM
     * @desc:
     * 参数说明: cans为候选数字列表,target为当前递归层的目标,temp为存放候选结果序列,re为存放结果的二维列表,num为当前所指向的候选中的下标
     */
    public void dfs(int[] cans, int target, List<Integer> temp, LinkedHashSet<ArrayList<Integer>> re, int num) {
        if (target == 0) {//递归结束条件,dfs到达叶节点
            re.add(new ArrayList<>(temp));//这里注意需要新建一个列表对象将temp包裹进去,因为这边不是基础类型,为引用传递
            return;
        } else {
            //还没有到达叶子节点时,对当前层的节点进行遍历,分别判断便进入相应子树
            for (int i = num; i < cans.length; i++) {
                //当当前层的结点值小于等于目标时,说明还需要进入子节点
                if (cans[i] != -1 && cans[i] <= target) {
                    //递归需要注意,对于当前层状态的保留,在从当前层进去,再从子树中回退回来时,当前层的一些变量需要还原
                    temp.add(cans[i]);
                    Integer t = cans[i];
                    cans[i] = -1;
                    dfs(cans, target - t, temp, re, i);
                    cans[i] = t;
                    temp.remove(temp.size() - 1);
                }
            }

        }

    }
//这是未简化的版本
    public void dfs(int[] cans, int target, List<Integer> temp, int tempSum, LinkedHashSet<ArrayList<Integer>> re, int num) {
        for (int i = num; i < cans.length; i++) {
            if (cans[i] == -1)
                continue;
            if (cans[i] + tempSum == target) {
                temp.add(cans[i]);
                re.add(new ArrayList<>(temp));
                if (temp.size() > 0)
                    temp.remove(temp.size() - 1);
            } else if (tempSum + cans[i] > target) {
                if (temp.size() > 0)
                    temp.remove(temp.size() - 1);
                break;
            } else {
                List<Integer> tt = new ArrayList<>(temp);
                tt.add(cans[i]);
                int t = cans[i];
                cans[i] = -1;
                dfs(cans, target, tt, tempSum + t, re, i);
                cans[i] = t;

            }
        }


    }

    public static void main(String argc[]) {
        List<List<Integer>> re = new combinationSum().combinationSum(new int[]{10, 1, 2, 7, 6, 1, 5}, 8);
        for (List<Integer> item : re) {
            for (Integer i : item)
                System.out.print(i);
            System.out.println("");
        }
    }
}


猜你喜欢

转载自blog.csdn.net/c630565685/article/details/89184015