字符串排列函数运行正常,数组排列函数失效,问题根源何在?
这问题的核心在于字符串和数组的类型本质差异:字符串是值类型(不可变),而数组是引用类型,你的代码逻辑没考虑到这一点,导致存入集合的数组引用最后都指向了同一个修改后的数组。
先看字符串版本为什么没问题
你的字符串swap函数里,每次都会把字符串转成数组,交换后再join成新字符串返回——因为字符串不可变,所以每次swap都会生成一个全新的字符串。递归过程中,每个分支传递的都是独立的字符串实例,存入Set的也是不同的字符串值,自然能得到正确的排列结果。
数组版本的问题出在哪
再看数组的swapA函数:它直接修改传入的原数组,然后返回同一个数组引用。递归时,你把数组存入Set的操作f.add(array),其实存的是数组的内存地址引用,而不是数组当前的内容。后续的swap操作会不断修改这个数组的内容,最后Set里所有“不同”的元素,实际上都是指向同一个数组的引用,最终显示的都是最后一次修改后的数组状态。
哪怕你在递归里console.log(array)能看到正确的内容,那也是因为日志输出的是当前时刻的数组快照,但Set里存的始终是引用,后续修改会同步影响所有引用指向的内容。
两种修正方案
方案1:存入集合时保存数组的副本
不需要修改swapA,只需要在把数组加入Set的时候,创建一个数组的浅拷贝,这样每个存入的都是独立的数组实例:
const permutationRecursive = function(array, l, r, f){ if(l==r){ // 存入数组的副本,而不是原引用 f.add([...array]); // 或者 array.slice() } else{ for(let i=l; i<=r; i++){ array = swapA(array, l, i) permutationRecursive(array, l+1, r,f) array = swapA(array, l, i) } } }
方案2:让swapA成为纯函数(返回新数组)
和字符串版本逻辑对齐,每次交换都生成新数组,不修改原数组:
const swapA = function(array, index1, index2){ // 创建原数组的副本,再交换副本的元素 const newArray = [...array]; const temp = newArray[index1]; newArray[index1] = newArray[index2]; newArray[index2] = temp; return newArray; }
这样递归时传递的都是新数组,存入Set的自然是不同的数组实例,无需修改存入逻辑。
验证修正后的结果
运行修改后的permutateOuter([1,2,3]),会得到正确的排列集合:Set(6) { [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,2,1], [3,1,2] }。
内容的提问来源于stack exchange,提问作者lfan3

