算法:递归
本文介绍递归思想
先看一道经典的题:
全排列
// 非重复数字:
/**
* @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时,进入函数就是从剩下的未用过的元素中拿一个确立第二个位置元素……
此题,非常之经典。相关算法,可以应用到游戏中去。
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
