如何重排数组避免连续重复元素?元素过多时拆分至其他数组
解决数组重排无连续重复元素并拆分剩余元素的问题
我来帮你搞定这个数组重排的问题!你需要的是把包含重复元素的数组,重排成无连续重复元素的数组,而且不能删除任何元素;如果某个元素重复次数太多,实在没法全部塞进一个无连续重复的数组里,就把剩下的元素放到单独的rest数组里,对吧?
先说说你之前尝试的那段代码问题在哪:那段递归函数是通过splice直接删除连续重复的元素,这完全不符合你的需求——我们要的是保留所有元素,只是调整位置或者拆分,不是删掉它们。
最优解决思路
核心思路是贪心策略+计数统计,步骤大概是这样:
- 第一步:先统计每个元素的出现次数,知道哪个元素重复得最多,这是判断能不能全部放进一个数组的关键。
- 第二步:用贪心的方式构建
merged数组——每次优先选择当前剩余次数最多、且和merged最后一个元素不同的元素放进去,这样能最大化利用数组空间,尽量避免出现连续重复。 - 第三步:当没有符合条件的元素可以放进
merged时,剩下的元素全部丢进rest数组。
具体代码实现(JavaScript)
function rearrangeArray(arr) { // 1. 统计每个元素的出现次数 const countMap = new Map(); arr.forEach(num => { countMap.set(num, (countMap.get(num) || 0) + 1); }); const merged = []; const rest = []; const tempCount = new Map(countMap); let lastAddedNum = null; // 2. 贪心构建merged数组 while (merged.length < arr.length) { let selectedNum = null; let maxRemainingCount = 0; // 找到当前剩余次数最多、且不等于上一个添加元素的项 for (const [num, count] of tempCount) { if (count > maxRemainingCount && num !== lastAddedNum) { maxRemainingCount = count; selectedNum = num; } } // 如果找不到符合条件的元素,说明剩下的都和lastAddedNum重复,直接丢去rest if (!selectedNum) { for (const [num, count] of tempCount) { rest.push(...Array(count).fill(num)); tempCount.delete(num); } break; } // 添加到merged,更新计数 merged.push(selectedNum); const newCount = tempCount.get(selectedNum) - 1; if (newCount === 0) { tempCount.delete(selectedNum); } else { tempCount.set(selectedNum, newCount); } lastAddedNum = selectedNum; } // 3. 把最后剩下的元素(如果有的话)丢进rest for (const [num, count] of tempCount) { rest.push(...Array(count).fill(num)); } return { merged, rest }; } // 测试你的示例 console.log(rearrangeArray([1,2,2,2,3,4,5])); // 输出示例:{ merged: [2,1,2,3,2,4,5], rest: [] }(顺序可能略有不同,但无连续重复) console.log(rearrangeArray([1,2,2,2,2,2,2,3,4])); // 输出示例:{ merged: [2,1,2,3,2,4,2], rest: [2,2] }
思路解释
- 统计次数是基础,我们需要知道每个元素还有多少个可以用;
- 贪心选择的逻辑能保证我们尽可能把多的元素先安排好,避免最后出现大量重复元素没法放置的情况;
- 当找不到能放进
merged的元素时,说明剩下的元素都和最后一个添加的元素重复,只能放到rest里,这时候就停止构建merged了。
这个方法能完美满足你的需求:既不删除任何元素,又能尽可能生成无连续重复的数组,实在排不开的元素也会被拆分到rest里。
内容的提问来源于stack exchange,提问作者Yoandry Collazo




