力扣回溯算法总结(排列,组合,子集)

202 阅读1分钟

组合: 若想选择一个后续不再重复选择,i=start,回溯时start: i+1,优化 i <= n-(k-path.length)+1。​

  1. 已经选择的元素个数:path.size();
  2. 还需要的元素个数为: k - path.size();
  3. 在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历

为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。

举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。

组合总和: 给定target,用target-nums[i]回溯,直到targrt=0。

无重复candidates:

有重复candidates:if(candidates[i-1] == candidates[i] && i > start) continue;

排列: 用uesd数组标记是否被选取过。

无重复nums:

有重复nums:if(nums[i-1] == nums[i] && used[i-1] == false && i > 0) continue;

子集: 路径上都res.push。

无重复nums:

有重复nums:if(nums[i-1] == nums[i] && i > start) continue;

1.组合 ( 只能选择一次)

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

var combine = function(n, k) {
    let res = []
    let path = []
    function backtracking(n,k,start){ //start开始取数的位置
        if(path.length==k){
            res.push([...path])
            return 
    }
        for(let i=start; i<=n-(k-path.length)+1; i++){
            path.push(i)
            backtracking(n,k,i+1)
            path.pop()
        }
    }
    backtracking(n,k,1)
    return res
};

2.组合总和Ⅲ ( 只能选择一次) ,给了target。

var combinationSum3 = function(k, n) {
    let res=[];
    let path=[];
    backtracking(path,n,k,0,1)
    return res;
    function backtracking(path,target,k,sum,start){
        if(target==0 && path.length==k){
            res.push([...path])
            return
        }
        // if(target<0) return;
        for(let i=start; i<=9-(k-path.length)+1; i++){
            path.push(i)
            backtracking(path,target-i,k,sum,i+1)     
            path.pop()
        }
    }
};

3.组合总和Ⅰ (无重复candinates)(可多次选取)

var combinationSum = function(candidates, target) {
    let path=[],res=[]
    candidates.sort
    backtracking(path,target,0,candidates)
    return res
    
    function backtracking(path,target,start,candidates){
        if(target==0){
            res.push([...path])
            return
        }
        if(target<0) return
        for(let i=start;i<candidates.length;i++){
            path.push(candidates[i])
            backtracking(path,target-candidates[i],i,candidates)
            path.pop()
        }
    }
};

4.组合总和Ⅱ (有重复candinates)(只能选取一次)

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

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

var combinationSum2 = function(candidates, target) {
    let res=[];
    let path=[]
    candidates.sort();
    backtracking(target,0,candidates)
    return res;
​
    function backtracking(target,start,candidates){
        if(target==0){
            res.push([...path])
            return
        }
        if(target<0) return
        for(let i=start; i<candidates.length; i++){
            if(candidates[i-1]==candidates[i] && i>start) continue;
            path.push(candidates[i]);
            backtracking(target-candidates[i],i+1,candidates);
            path.pop();
        }
    }
};

5.全排列 (无重复nums)

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

var permute = function(nums) {
    let path=[],res=[]
    backtracking([])
    return res
    function backtracking(used){
        if(path.length==nums.length){
            res.push([...path])
            return
        }
        for(let i=0; i<nums.length; i++){
            if(!used[i]){
                path.push(nums[i])
                used[i]=true
                backtracking(used)
                path.pop()
                used[i]=false
            }
        }
    }
​
};

6.全排列Ⅱ (有重复nums)

给定一个可包含重复数字的序列 nums ,按任意顺序返回所有不重复的全排列。

var permuteUnique = function(nums) {
    nums.sort();
    let res=[],path=[];
    let k=nums.length;
    backtracking([]);
    return res;
​
    function backtracking(used){
        if(path.length==k){
            res.push([...path]);
            return;
        }
        for(let i=0;i<k;i++){
            if(nums[i-1]==nums[i] && used[i-1]==false && i>0) continue;
            if(!used[i]){
                path.push(nums[i]);
                used[i]=true;
                backtracking(used);
                path.pop();
                used[i]=false;
            }
        }
    }
};

7.子集 (无重复nums)

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

var subsets = function(nums) {
    let res=[],path=[];
    let k=nums.length;
    backtracking(0);
    return res;
​
    function backtracking(begin){
        res.push([...path])
        for(let i=begin; i<k; i++){
            path.push(nums[i])
            backtracking(i+1)
            path.pop()
        }
    }
};

8.子集Ⅱ (有重复nums)

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

var subsetsWithDup = function(nums) {
    let res=[],path=[];
    let k=nums.length;
    nums.sort();
    backtracking(0);
    return res;
​
    function backtracking(begin){
        res.push([...path]);
        for(let i=begin;i<k;i++){
            if(i>begin && nums[i-1]==nums[i]) continue
            path.push(nums[i]);
            backtracking(i+1);
            path.pop();
        }
    }
};

\