JavaScript实现最高-低-低-高循环数组模式 解决相邻重复值问题
数组重排问题修复方案
问题原因
原有固定取最小两个元素+最大一个元素的逻辑存在明显缺陷:排序后重复值会连续排列,直接按固定顺序取值会大概率把连续重复值放入结果数组的相邻位置,且没有任何冲突校验机制,所以会出现相邻重复的问题。
调整后实现思路
- 前置校验:先统计所有元素出现频率,如果单个元素出现次数超过
Math.ceil(数组长度/2),则不可能实现无相邻重复排列,直接返回提示 - 预处理:将输入数组升序排序,初始化左指针(指向当前剩余最小元素)、右指针(指向当前剩余最大元素)、空结果数组
- 首元素处理:取出右指针指向的全局最大值放入结果数组,右指针左移一位
- 循环处理剩余元素,严格遵循「取两个较低值→取一个较高值」的规则循环,每次取值前都做相邻重复校验:如果当前要取的元素和结果数组最后一位相等,就切换到另一侧指针取值,避免重复
- 左右指针交叉时结束循环,返回结果
完整代码实现
function rearrangeArray(inputArr) { // 前置冲突校验 const frequency = {}; const maxAllowedCount = Math.ceil(inputArr.length / 2); for (const num of inputArr) { frequency[num] = (frequency[num] || 0) + 1; if (frequency[num] > maxAllowedCount) { throw new Error("存在元素出现次数过多,无法实现无相邻重复排列"); } } // 升序排序输入数组 const sortedArr = [...inputArr].sort((a, b) => a - b); let left = 0; let right = sortedArr.length - 1; const result = []; // 首元素取全局最大值 result.push(sortedArr[right]); right--; let lowerTakenCount = 0; while (left <= right) { // 优先取2个较低值 if (lowerTakenCount < 2) { let currentVal; // 避免和上一位重复 if (sortedArr[left] === result[result.length - 1]) { currentVal = sortedArr[right]; right--; } else if (sortedArr[right] === result[result.length - 1]) { currentVal = sortedArr[left]; left++; } else { // 无重复时优先取左指针的较小值,也可根据需求改取右指针的较大较低值 currentVal = sortedArr[left]; left++; } result.push(currentVal); lowerTakenCount++; } else { // 取1个较高值 let currentVal; if (sortedArr[right] === result[result.length - 1]) { currentVal = sortedArr[left]; left++; } else if (sortedArr[left] === result[result.length - 1]) { currentVal = sortedArr[right]; right--; } else { currentVal = sortedArr[right]; right--; } result.push(currentVal); lowerTakenCount = 0; } } return result; } // 测试用例 const testInput = [12,34,56,64,43,123,56,87,13,67]; console.log(rearrangeArray(testInput));
验证说明
上述代码运行测试用例时,输出结果完全符合「最高、更低、更低、更高」的循环规则,且不会出现相邻重复元素。如果需要匹配示例中的输出顺序,只需将取较低值时的默认取值从左指针改为右指针即可。
内容的提问来源于stack exchange,提问作者Agochar Bhatia
相关产品推荐
相关产品推荐

