我有32个数字组成的数组[1,2,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,7,8,9,10, 10,11,12,13,13,14,14,15,16,17,17]

我想将此数组划分为8个子数组,每个子数组的大小为4,这样子数组就不会有重复的元素。

我可以通过几种方式做到这一点?生成所有排列和单个随机排列的最佳解决方案是什么。子数组的顺序无关紧要。每个子数组中元素的顺序也没有。

对于我最初的问题,我不需要生成所有排列。每次运行程序时,我只需要生成一个随机排列即可。

我的方法是使用Fisher-Yates算法随机地对数组进行混洗,并不断对其进行改组,直到获得所有8个没有重复元素的子数组。当然,这不是最好的方法。

作为解决方案的一部分,我对数组进行了混洗,并从此混洗后的数组开始向子数组一个接一个地添加元素。如果任何子数组已经有一个数字,那么我会不断从混洗后的数组中跳过元素,直到达到一个不是我的子数组的数字。在某些情况下,此方法将失败。

我尝试过的伪代码

let shuffledArray = shuffle(originalArray);
let subArrays = [];
for (let i = 0; i < 8; i++) {
    subArrays[i] = [];
    for (let j = 0; j < 32; j++) {
        if (!subArrays[i].contains(shuffledArray[j]) && !shuffledArray[j].used) {
            subArrays[i].push(shuffledArray[j])
            shuffledArray[j].used = true;
        }
        if (subArrays[i].length == 4) {
            break;
        }
    }
}

 if subArrays has any sub array such that it has duplicate elements then repeat above steps
 else we have generated a random permutation

如您所见,当将所有重复的数字混排在一起后,上述方法将失败,因此,作为hack,我一次又一次重复所有步骤,直到得到结果。

我正在使用JavaScript,但是任何语言的答案都可以,只要可以将其转换为JavaScript。

如果任何人都可以为N个元素和K个组提供通用的解决方案,那也很好。

这是我在SO提出的第一个问题。随时编辑/建议改进。

最佳答案

一种选择是先将您的列表分成相同编号的组,然后按长度排序。然后,您可以通过从最长,第二最长,第三最长,第四最长的每个组中选取元素来进行分组。清空子组时,将其删除。

这是JS实现:

function partition(arr, N){
    // group items together and sort by length
    // groups will be [[5, 5, 5, 5, 5], [4, 4, 4, 4], ...]

    let groups = Object.values(l.reduce((obj, n) =>{
        (obj[n] || (obj[n] = [])).push(n)
        return obj
    }, {})).sort((a,b) => b.length - a.length)

    let res = []
    while(groups.length >= N){
        let group = []
        let i = 0
        while (group.length < N){
           group.push(groups[i].pop())
           if (groups[i].length < 1) groups.splice(i, 1)
           else i++
        }
        res.push(group)
    }
    return res
}
let l = [1,2,3,4,4,4,4,5,5,5,5,5,6,6,7,7,7,7,8,9,10,10,11,12,13,13,14,14,15,16,17,17]


console.log(partition(l, 4).map(arr => arr.join(',')))

// with 5
console.log(partition(l, 5).map(arr => arr.join(',')))

10-04 20:57
查看更多