本文介绍递归思想

先看一道经典的题:

全排列

// 非重复数字:
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var permute = function(nums) {
    let res = []
    let used = new Array(nums.length).fill(0)
    const f = (n1) => {
        if(n1.length === nums.length) {
            // let temp = JSON.parse(JSON.stringify(n1))
            res.push([...n1]) 
            // 此处发现一个很懵逼的问题,若写成res.push(n1),结果居然都为空。。。
        }
        for(let i = 0; i < nums.length;i++) {
            if(used[i] === 1) continue
            n1.push(nums[i])
            used[i] = 1
            f(n1)
            n1.pop()
            used[i] = 0
        }
    }
    f([])
    return res
};
// 有重复数字:
// 此种情况下,最简单的方法就是,在无重复数字的基础上,塞结果之前做一个判断,可奇怪的是,一个判断居然超时。。。

var permute = function(nums) {
    let res = []
    let used = new Array(nums.length).fill(0)
    const f = (n1) => {
        if(n1.length === nums.length) {
            console.log('n1:',n1)
            console.log('n1clice:',n1.slice())
            // let temp = JSON.parse(JSON.stringify(n1))
            if(JSON.stringify(res).indexOf(JSON.stringify([...n1])) === -1) {
                res.push([...n1]) 
            }
            // 此处发现一个很懵逼的问题,若写成res.push(n1),结果居然都为空。。。
        }
        for(let i = 0; i < nums.length;i++) {
            if(used[i] === 1) continue
            n1.push(nums[i])
            used[i] = 1
            f(n1)
            n1.pop()
            used[i] = 0
        }
    }
    f([])
    return res
};
·

递归正常人确实理解困难,但往往最简洁

许久之后再来回首,依旧没能写出来,一度思考递归的意义何在????
多年后回来解答:拿非重复数字代码举例,f([])为起始入口。f函数的代码是很简洁很简单的,就是一个判断语句和一个for循环,但是直到今天,我才真正悟明白了该函数的意义。我以前一直没闹明白一点,对于人脑而言,给定一个数组,我们是怎么给出该数组的全排列的?很简单嘛,假使数组长度为3,那么我们首先确定第一个位置,有三种可能,第二个位置两种可能,第三个位置,一种可能,3x2x1=6,得到六祖全排列数组。我一直以来的困惑在于,如何把这个过程程序化。递归的意义就在于此。函数的输入是一个[]作为起始,表示当前路径长度为0。进入函数体后,通过for循环遍历原数组,如果某元素没有用过,取出来塞入路径数组,打上used标记,再以当前路径作为f输入递归。

f的输入数组长度为0时,进入函数就是确立第一个位置,输入数组长度为1时,进入函数就是从剩下的未用过的元素中拿一个确立第二个位置元素……

此题,非常之经典。相关算法,可以应用到游戏中去。