【发布时间】:2021-11-06 05:35:03
【问题描述】:
我已经使用 JavaScript 实现了Steinhaus-Johnson-Trotter Algorithm,这个实现只计算数字数组的所有排列。
当数组的大小 >= 4 时,算法会产生重复的结果。我明白它为什么会产生结果,但我不确定如何避免这种情况,因为创建这些重复项满足算法原则。
class Direction {
constructor(dir) {
if(dir === 'LEFT' || dir === 'RIGHT') {
this.dir = dir
}
}
setDir(dir) {
if(dir === 'LEFT' || dir === 'RIGHT') {
this.dir = dir
}
}
switchDir() {
switch(this.dir) {
case 'LEFT':
this.dir = 'RIGHT'
break
case 'RIGHT':
this.dir = 'LEFT'
break
}
}
}
var permute = function(nums) {
if(nums.length === 1) return [nums]
if(nums.length === 2) return [nums, [nums[1], nums[0]]]
// I'm only worried about arrays up to length 6
const facts = [1, 2, 6, 24, 120, 720]
const dirs = {}
const max = Math.max(...nums)
nums.forEach(v => {
dirs[v] = new Direction('LEFT')
})
const res = []
const move = (n) => {
const i = nums.indexOf(n)
const ele = dirs[n]
switch(ele.dir) {
case 'LEFT':
[nums[i], nums[i - 1]] = [nums[i - 1], nums[i]]
break
case 'RIGHT':
[nums[i], nums[i + 1]] = [nums[i + 1], nums[i]]
break
}
if(n === max) {
return
}
nums.forEach(v => {
if(v > n) dirs[v].switchDir()
})
}
// Number is said to mobile if it can move to its direction
const isMobile = (n) => {
const d = dirs[n].dir
if(d === 'LEFT' && nums.indexOf(n) !== 0) {
return true
}
if(d === 'RIGHT' && nums.indexOf(n) !== nums.length - 1) {
return true
}
return false
}
// Finding mobiles means finding the largest number and checking if it is mobile
const findMobile = () => {
// If not max then lets find the next largest mobile
var num = Number.MIN_VALUE
nums.forEach(v => {
if(isMobile(v) && v > num) {
num = v
}
})
return num
}
// Loop through the max length factorial, included up to only 6 as req
while(res.length < facts[nums.length - 1]) {
const next = findMobile()
move(next)
res.push([...nums])
console.log(res)
}
return res
};
测试用例:
Test 1:
Input: [1,2,3]
Result: [[1,3,2],[3,1,2],[3,2,1],[2,3,1],[2,1,3],[1,2,3]], Passed
Test 2:
Input: [5,4,6,2]
Result: [
[ 5, 6, 4, 2 ], [ 6, 5, 4, 2 ],
[ 5, 6, 4, 2 ], [ 5, 4, 6, 2 ],
[ 5, 4, 2, 6 ], [ 4, 5, 2, 6 ],
[ 4, 5, 6, 2 ], [ 4, 6, 5, 2 ],
[ 6, 4, 5, 2 ], [ 6, 4, 2, 5 ],
[ 4, 6, 2, 5 ], [ 4, 2, 6, 5 ],
[ 4, 2, 5, 6 ], [ 4, 2, 6, 5 ],
[ 4, 6, 2, 5 ], [ 6, 4, 2, 5 ],
[ 4, 6, 2, 5 ], [ 4, 2, 6, 5 ],
[ 4, 2, 5, 6 ], [ 4, 5, 2, 6 ],
[ 4, 5, 6, 2 ], [ 4, 6, 5, 2 ],
[ 6, 4, 5, 2 ], [ 6, 5, 4, 2 ]
], Failed
如结果所示,算法会产生重复,但如前所述,重复之间的步骤满足算法。
我对算法的理解:
所有元素从右到左开始:
即。
我们找到下一个最大的“移动”数字,在本例中为 4。然后我们将其移向它的方向。
即。
重复这个过程。
如果移动的手机号码小于另一个号码,则较大的号码交换方向。
编辑 问题我已经解决了,就是不检查手机号大小和要换号的问题。
【问题讨论】:
-
这并不完美,但您可以使用Set 来获得独特的解决方案。
-
你是说对于长度为 4 的数组,它会产生 48 个结果(24 个不同)或 24 个结果(12 个不同)。
-
如果你能读懂 Python 代码,我会展示工作实现
-
另请注意,初始数组应排序 - 否则您需要正确的方向数组
-
@RBarryYoung 它正在产生 24 个结果,其中有一些重复。
标签: javascript arrays algorithm permutation