(算法)递归与回溯

94 阅读1分钟

全排列问题

从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。

示例:

输入: [1,2,3]
输出: [
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]]

题解:

/**
* @param {number[]} nums
* @return {number[][]}
*/
const permute = function(nums){
   const res = [];
   const cur = [];
   const visited = {};
   
   const dfs = (nth) => {
       if(nth === nums.length){
           res.push(cur.slice());
           return;
       }
       
       for(let i = 0; i < nums.length; i++){
           if(!visited[nums[i]]){
               visited[nums[i]] = true;
               cur.push(nums[i]);
               //递归
               dfs(nth + 1);
               //回溯
               cur.pop();
               //去除已使用标志
               visited[nums[i]] = false;
           }
       }
   }
   //从索引0开始
   dfs(0);
   return res;
}

规则:

“重复”的内容,就是递归式;“重复”的终点,就是递归边界。

组合问题

给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。

示例:

说明:解集不能包含重复的子集。
输入: nums = [1,2,3]
输出:
[[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]]

题解:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
const subsets = function(nums){
   const res = [];
   const subset = [];
   
   const dfs = (index) => {
       res.push(subset.slice());
       
       for(let i = index; i < nums.length; i++){
           subset.push(nums[i]);
           
           // 基于当前数字存在于组合中的情况,进一步 dfs
           dfs(i + 1);
           //回溯,不参与填坑则出坑
           subset.pop();
       }
   }
   
   dfs(0);
   
   return res;
}

规则:

穷举出现了,大概率会用到 DFS。

限定组合问题

给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。

示例:

输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

题解:

/**
 * @param {number} n
 * @param {number} k
 * @return {number[][]}
 */
const combine = function(n, k){
    const res = [];
    const subset = [];
    
    const dfs = (index) => {
        //处理边界
        if(subset.length === k){
            res.push(subset.slice());
            return;
        }
        
        for(let i = index; i <= n; i++){
            subset.push(i);
            //基于当前数进行递归
            dfs(i + 1);
            //回溯,移除当前不符组合元素
            subset.pop();
        }
    }
    
    
    return res;
}

规则:

DFS 算法其实就是回溯思想的体现。