回溯法

回溯法动态规划题目
https://www.cnblogs.com/jiangchen/p/5930049.html
回溯法概念(http://www.cnblogs.com/jiangchen/p/5393849.html

LeetCode 39. Combination Sum (组合的和)

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

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

Note:

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

For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word;">[
[7],
[2, 2, 3]
]</pre>
题目标签:Array

题目给了我们一个candidates array 和一个 target, 让我们从array 里找到所有的组合,它的和是等于target的。任何组合只要是它的和等于target的话,都需要找到,但是不需要重复的。这道题中是可以重复利用一个数字的,那么我们就需要每次都代入同一个数字,直到它之和达到target 或者它超过了target, 然后在倒退回去一个数字,继续找下一个数字,这种情况肯定是要用递归了。这里是backtracking,每次倒退回一个数字,需要继续递归下去,在倒退,一直重复直到搜索了所有的可能性。

我们可以看原题中的例子:

[2,3,6,7] target 7

2 选2,sum = 2

2+2 选2,sum = 4

2+2+2 选2,sum = 6

2+2+2+2 选2,sum = 8 这时候 sum已经超出target,需要返回到上一个数字

2+2+2+3 选3,sum = 9, 也超出了target, 这里我们可以发现,如果是sorted array的话,从小到大,只要一次超出,后面的数字必然也会超出target,所以可以在第一次超出的时候就直接跳出这一个迭代

2+2+3 选3,sum = 7,等于target, 此时返回并且跳出这一个迭代,因为后面的数字肯定超出(array里不会有重复的数字)

2+3 选3,sum = 5,小于target,继续递归同一个数字

2+3+3 选3,sum = 8,超出target,返回上一个数字

2+6 选6,sum = 8,超出target,返回上一个数字

3 选3,这里继续从3开始递归

...

...

...

我们可以看出,一开始有一个迭代从2,一直到7,然后把每一个数字递归下去,包括它自己,每次递归下去的数字,会继续有一个迭代,一旦超出或者等于了,返回前面一个数字继续递归。所以把array sort一下就可以提早跳出那一轮的迭代。
数组中的每个数字可以用多次:

public List<List<Integer>>  getAllCombination(int[] arr,int target){
        List<List<Integer>> resList=new ArrayList<List<Integer>>();
        List<Integer> curList=new ArrayList<>();
        Arrays.sort(arr);
        backTracking(resList,curList,arr,target,0);
        return resList;
    }

    /**
     * @param resList
     * @param curList
     * @param arr
     * @param target
     * @param i
     *<p>Description: </p>  
     */
    private boolean backTracking(List<List<Integer>> resList,
            List<Integer> curList, int[] arr, int remain, int start) {

        if(remain==0){
            resList.add(new ArrayList<Integer>(curList));
            return false;
        }
        if(remain<0){
            return false;
        }
        else{
            for(int i=start;i<arr.length;i++){
                curList.add(arr[i]);
                boolean flag=backTracking(resList, curList, arr, remain-arr[i], i);
                curList.remove(curList.size()-1);
                if(!flag){
                    break;
                }
            }
            return true;

        }
    }

如果数组中不包含重复的元素的,且每个元素只能用一次。

public List<List<Integer>>  getAllCombinationUnduplicate(int[] arr,int target){
        List<List<Integer>> resList=new ArrayList<List<Integer>>();
        List<Integer> curList=new ArrayList<>();
        Arrays.sort(arr);
        backTrackingUnduplicate(resList,curList,arr,target,0);
        return resList;
    }
    private boolean backTrackingUnduplicate(List<List<Integer>> resList,
            List<Integer> curList, int[] arr, int remain, int start) {

        if(remain==0){
            resList.add(new ArrayList<Integer>(curList));
            return false;
        }
        if(remain<0){
            return false;
        }
        else{
            for(int i=start;i<arr.length;i++){
                
                curList.add(arr[i]);
                boolean flag=backTrackingUnduplicate(resList, curList, arr, remain-arr[i], i+1);
                curList.remove(curList.size()-1);
                if(!flag){
                    break;
                }
            }
            return true;

        }
    }

数组中包含有重复的元素,且每个元素只能用一次。最后的结果中不含重复的结果集。
Combination Sum 2

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.
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]
]

public List<List<Integer>>  getAllCombinationUnduplicate(int[] arr,int target){
        List<List<Integer>> resList=new ArrayList<List<Integer>>();
        List<Integer> curList=new ArrayList<>();
        Arrays.sort(arr);
        backTrackingUnduplicate(resList,curList,arr,target,0);
        return resList;
    }
    private boolean backTrackingUnduplicate(List<List<Integer>> resList,
            List<Integer> curList, int[] arr, int remain, int start) {

        if(remain==0){
            resList.add(new ArrayList<Integer>(curList));
            return false;
        }
        if(remain<0){
            return false;
        }
        else{
            for(int i=start;i<arr.length;i++){
                curList.add(arr[i]);
                boolean flag=backTrackingUnduplicate(resList, curList, arr, remain-arr[i], i+1);
                curList.remove(curList.size()-1);
                if(!flag){
                    break;
                }
                while(i<arr.length-1 && arr[i]==arr[i+1]){
                    i++;
                }
            }
            return true;

        }
    }

比如数组a={1,1,1,1,2},target=4.用上面解法的过程见下图:


image.png

Combination Sum 3

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.

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]]

public List<List<Integer>>  getAllCombinationUnduplicate(int[] arr,int target,int k){
        List<List<Integer>> resList=new ArrayList<List<Integer>>();
        List<Integer> curList=new ArrayList<>();
        Arrays.sort(arr);
        int count=0;
        backTrackingUnduplicate(resList,curList,arr,target,0,k);
        return resList;
    }
    private boolean backTrackingUnduplicate(List<List<Integer>> resList,
            List<Integer> curList, int[] arr, int remain, int start,int k) {

        if(remain==0 && curList.size()==k){
            
            resList.add(new ArrayList<Integer>(curList));
            return false;
        }
        if(remain<0){
            return false;
        }
        else{
            for(int i=start;i<arr.length;i++){
                if(remain-arr[i]>0 && curList.size()+1==k ){
                    continue;
                }
                curList.add(arr[i]);
                boolean flag=backTrackingUnduplicate(resList, curList, arr, remain-arr[i], i+1,k);
                curList.remove(curList.size()-1);
                if(!flag){
                    break;
                }
                while(i<arr.length-1 && arr[i]==arr[i+1]){
                    i++;
                }
            }
            return true;

        }
    }

Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

    public List<List<Integer>> getAllCombinations(int[] a,int k){
        List<List<Integer>> resList = new ArrayList<>();
        List<Integer> curList=new ArrayList<>();
        Arrays.sort(a);
        backTrack(resList, curList, a, 0,k);
        return resList;
    }
    /**
     * @param resList
     * @param curList
     * @param a
     * @param i
     *<p>Description: </p>  
     */
    private void backTrack(List<List<Integer>> resList,
            List<Integer> curList, int[] a, int start,int k) {
        if(curList.size()==k){
            resList.add(new ArrayList(curList));
            return;
        }
        
        for(int i=start;i<a.length;i++){
            curList.add(a[i]);
            backTrack(resList, curList, a, i+1, k);
            curList.remove(curList.size()-1);
        }
        //return;写不写的区别是啥
        
    }

Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below.


image.png

Input:Digit string "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

public List<String> getStringCombinaList(String input){
        List<String> resList=new ArrayList<>();
        StringBuilder sb=new StringBuilder();
        Map<Character,String> map=new HashMap();
        map.put('2', "abc");
        map.put('3', "def");
        map.put('4', "ghi");
        map.put ('5', "jkl");
        map.put ('6', "mno");
        map.put ('7', "pqrs");
        map.put ('8', "tuv");
        map.put ('9', "wxyz");
        int start=0;
        backTrackHelper(resList,sb,input,map,start);
        return resList;
        
        
        
    }
    /**
     * @param resList
     * @param sb
     * @param input
     * @param map
     * @param start
     *<p>Description: </p>  
     */
    private void backTrackHelper(List<String> resList, StringBuilder sb,
            String input, Map<Character, String> map, int start) {

        if(sb.length()==input.length()){
            resList.add(sb.toString());
            return;
        }
        String temp=map.get(input.charAt(start));
        for(int i=0;i<temp.length();i++){
            sb.append(temp.charAt(i));
            backTrackHelper(resList, sb, input, map, start+1);
            sb.deleteCharAt(sb.length()-1);
        }
    }

Given a set of distinct integers, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,3], a solution is:

[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
解法1:回溯

public List<List<Integer>> getAllSet(List list){
       List<List<Integer>> resList=new ArrayList();
       if(list.size()==0){
           return resList;
       }
       List curList=new ArrayList<>();
       backTrackSubset(resList,list,curList,0);
       return resList;
   }

   /**
    * @param resList
    * @param list
    * @param i
    *<p>Description: </p>  
    */
   private void backTrackSubset(List<List<Integer>> resList, List list,List curList, int current) {

       resList.add(new ArrayList(curList));
       
       for(int i=current;i<list.size();i++){
           curList.add(list.get(i));
           backTrackSubset(resList, list, curList, i+1);
           curList.remove(curList.size()-1);
       }
   }

解法2:动态规划(有个问题没有解决)
Java集合的拷贝构造函数只提供浅拷贝而不是深拷贝

public Set<Set<Integer>> getAllSubSetDyn(int[] a,int n){
        Set<Set<Integer>> resSet=new HashSet<>();
        if(n==0){
        resSet.add(new HashSet<>());
        return resSet;
        }
        Set<Set<Integer>> set=getAllSubSetDyn(a, n-1);
        for(Set<Integer> s:set){
            Set<Integer> setCopy=new HashSet<>(s);//集合默认是浅拷贝
            setCopy.add(a[n-1]);
            resSet.add(new HashSet<Integer>(setCopy));//    resSet.add(setCopy);

            resSet.add(new HashSet<Integer>(s));
        }
        return resSet;
    }

Subsets II (contains duplicates)

Given a collection of integers that might contain duplicates, nums, return all possible subsets.

Note: The solution set must not contain duplicate subsets.

For example,
If nums = [1,2,2], a solution is:

[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]

public List<List<Integer>> getAllSetDuplicate(int[] a){
       List<List<Integer>> resList=new ArrayList<>();

       if(a.length<=0){
           return resList;
       }
       Arrays.sort(a);
       List curList=new ArrayList<>();
       backTrackSubsetDuplicate(resList,curList,a,0);
       return resList;
       
   }
   /**
    * @param resList
    * @param curList
    * @param a
    * @param i
    *<p>Description: </p>  
    */
   private void backTrackSubsetDuplicate(List<List<Integer>> resList,
           List curList, int[] a, int start) {

       resList.add(new ArrayList<>(curList));
       for(int i=start;i<a.length;i++){
           curList.add(a[i]);
           backTrackSubsetDuplicate(resList, curList, a, i+1);
           curList.remove(curList.size()-1);
           while(i<a.length-1 && a[i]==a[i+1]){
               i++;
           }
       }
   }

Given a collection of distinct numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:

[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

public List<List<Integer>> getPermutations(int[] a){
        List<List<Integer>> resList=new ArrayList<>();
        if(a.length<=0){
            return resList;
        }
        
        List<Integer> curList=new ArrayList<>();
        backtrackPermutation(resList,curList,a);
        return resList;
    }
    /**
     * @param resList
     * @param curList
     * @param a
     *<p>Description: </p>  
     */
    private void backtrackPermutation(List<List<Integer>> resList,
            List<Integer> curList, int[] a) {

        if(curList.size()==a.length){
            resList.add(new ArrayList<>(curList));
        }
        
        for(int i=0;i<a.length;i++){
            if(curList.contains(a[i])){
                continue;
            }
            curList.add(a[i]);
            backtrackPermutation(resList, curList, a);
            curList.remove(curList.size()-1);
        }
    }

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

For example,
[1,1,2] have the following unique permutations:

[
[1,1,2],
[1,2,1],
[2,1,1]
]

    
    public List<List<Integer>> getPermutationDuplicate(int a[]){
        List<List<Integer>> resList=new ArrayList<>();
        Arrays.sort(a);
        List<Integer> curList=new ArrayList<>();
        boolean[] flag=new boolean[a.length];
        backTrackPermutationDup(resList,curList,a,flag);
        return resList;
    }

    /**
     * @param resList
     * @param curList
     * @param a
     *<p>Description: </p>  
     */
    private void backTrackPermutationDup(List<List<Integer>> resList,
            List<Integer> curList, int[] a,boolean[] flag) {

        if(curList.size()==a.length){
            resList.add(new ArrayList<Integer>(curList));
        }
        
        
        for(int i=0;i<a.length;i++){
            if(flag[i]){
                continue;
            }
            
            curList.add(a[i]);
            flag[i]=true;
            
            backTrackPermutationDup(resList, curList, a, flag);
            curList.remove(curList.size()-1);
            flag[i]=false;
            while(i<a.length-1 && a[i]==a[i+1]){
                i++;
            }
        }
    }

Given a binary tree, return all root-to-leaf paths.

Note: A leaf is a node with no children.

Example:

Input:

1
/
2 3

5

Output: ["1->2->5", "1->3"]

Explanation: All root-to-leaf paths are: 1->2->5, 1->3

public List<String> getAllPaths(TreeNode root){
        List<String> list=new ArrayList<String>();
        if(root == null){
            return list;
        }
        StringBuilder sb=new StringBuilder();
        backTracking(root,list,sb);
        return list;
        
    }
    /**
     * @param root
     * @param list
     * @param sb
     *<p>Description: </p>  
     */
    private void backTracking(TreeNode root, List<String> list, StringBuilder sb) {

        if(root == null){
            return;
        }
        int length=sb.length();

        if(root.getLeft() == null && root.getRight() == null){
            sb.append(root.getValue());
            list.add(sb.toString());
        }
        else{
            sb.append(root.getValue());
            sb.append("->");
            backTracking(root.getLeft(), list, sb);
            backTracking(root.getRight(), list, sb);
        }
    
        sb.setLength(length);//截取
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,723评论 0 33
  • iOS面试中熟悉常见算法 1、 对以下一组数据进行降序排序(冒泡排序)。“24,17,85,13,9,54,76,...
    修一辰阅读 414评论 0 0
  • 通信原理(学习笔记) 第二章 信道 第3讲 信道的概念和实际信道 信道的定义信道:信号传输的通道信号处理的角度:信...
    快乐的大脚aaa阅读 1,041评论 0 0
  • 今天主要学了如何利用windows操作系统的漏洞进行后门提权。主要用到的工具有nessus、metasploit、...
    kotw_zjc阅读 1,520评论 0 0
  • 1、lvs-tun模式 转发方式:不修改请求报文的IP首部(源IP为CIP,目标IP为VIP),而在原IP报文之外...
    阿丧小威阅读 227评论 0 0