如何用JavaScript实现Best Fit算法?现有Bin Packing函数问题排查
最佳适配(Best Fit)装箱算法实现问题
我写了一个用Best Fit算法解决装箱问题的JavaScript函数,但输出结果不符合预期:元素大量重复,排序效果差,比如"CSS"明明能放进第一个子数组,却被单独放在一个数组里。下面是我的代码和错误输出:
const bestFit = (stringArray, maxWidth) => { let results = [[]]; stringArray.sort((a, b) => b.length - a.length); // 从大到小排序 // ['TailwindCSS', 'Woocommerce', 'typescript', 'three.js', 'threlte', 'svelte', 'Python', 'CSS'] try { stringArray.forEach((str, strIndex) => { if (!results[0][0]) { results[0].push(str) } else { const tempArray = []; results.forEach((_elm, _idx) => { tempArray.push({ index: _idx, data: _elm }); }); tempArray.sort((a, b) => { return a.data.join().length - b.data.join().length; // 从小到大排序 }) for (const [_tx, _obj] of tempArray.entries()) { const availableSpace = (_obj.data.join('').length + str.length) <= maxWidth; if (availableSpace) { results[_obj.index].push(str); continue; } else { if (tempArray[_tx + 1]) { continue; } else { results.push([str]); } } } } }); } catch (e) { console.log(e); } return results; } const technologies = ['svelte', 'typescript', 'threlte', 'three.js', 'TailwindCSS', 'Python', 'Woocommerce', 'CSS']; const MAX_LENGTH = 20; const results = bestFit(technologies, MAX_LENGTH); console.log(results); // 错误输出: // [ // ["TailwindCSS", "three.js",], // ["Woocommerce", "three.js",], // ["typescript", "three.js",], // ["threlte", "svelte", "Python",], // ["svelte", "Python", "CSS",], // ["Python", "CSS",], // ["CSS",], // ]
问题根源
- 遍历逻辑错误:找到第一个能放下元素的箱子后没有终止循环,导致后续所有符合条件的箱子都会重复添加同一个元素,这是重复元素的核心来源。
- Best Fit逻辑偏离:原代码只是按已用空间从小到大遍历箱子,没有找到剩余空间最小且能容纳当前元素的最优箱子,不符合Best Fit算法的核心要求。
- 空间计算冗余:用
join('').length计算已用空间,不如直接求和字符串长度直观,虽然结果一致,但逻辑上不够清晰。
修正后的代码
const bestFit = (stringArray, maxWidth) => { const results = []; // 复制原数组并按长度降序排序(Best Fit Decreasing优化步骤) const sortedStrings = [...stringArray].sort((a, b) => b.length - a.length); sortedStrings.forEach(str => { let bestBoxIndex = -1; let minRemainingSpace = Infinity; // 遍历现有箱子,找到剩余空间最小且能放下当前元素的箱子 for (let i = 0; i < results.length; i++) { const box = results[i]; const usedSpace = box.reduce((total, s) => total + s.length, 0); const remainingSpace = maxWidth - usedSpace; if (remainingSpace >= str.length && remainingSpace < minRemainingSpace) { bestBoxIndex = i; minRemainingSpace = remainingSpace; } } if (bestBoxIndex !== -1) { results[bestBoxIndex].push(str); } else { // 没有合适的箱子,新建一个 results.push([str]); } }); return results; }; const technologies = ['svelte', 'typescript', 'threlte', 'three.js', 'TailwindCSS', 'Python', 'Woocommerce', 'CSS']; const MAX_LENGTH = 20; const results = bestFit(technologies, MAX_LENGTH); console.log(results);
修正说明
- 还原Best Fit核心逻辑:遍历所有箱子时,专门记录剩余空间最小且能容纳当前元素的箱子,确保元素放入最优位置。
- 终止重复添加:找到最优箱子后直接放入,不再继续遍历其他箱子,彻底解决元素重复问题。
- 简化空间计算:用
reduce直接求和箱子内字符串长度总和,逻辑更清晰,避免不必要的字符串拼接操作。 - 优化初始处理:去掉冗余的初始箱子判断,直接从空数组开始构建,代码更简洁。
正确输出
[ ["TailwindCSS", "CSS"], ["Woocommerce", "Python"], ["typescript", "svelte"], ["three.js", "threlte"] ]
可以看到"CSS"被正确放入第一个箱子(TailwindCSS长度10 + CSS长度3 = 13 ≤ 20),没有重复元素,装箱效率符合预期。
内容的提问来源于stack exchange,提问作者a3k
相关产品推荐
相关产品推荐

