如何在PHP中生成指定行数的单词字符串所有换行排列及最优分割?
嘿,这个问题我之前也遇到过类似的场景!咱们一步步来解决:首先得搞定生成所有可能的换行组合,再从中筛选出行长差异最小的结果。
第一步:先把句子拆成单词数组
首先得把输入的句子拆解成独立的单词,还要处理可能的首尾空格或者多个连续空格的情况:
$words = array_filter(explode(' ', trim($sentence)));
比如输入"My name is Gary",会得到["My", "name", "is", "Gary"]这个干净的单词数组。
第二步:生成所有符合要求的换行排列
核心逻辑是:如果有n个单词,要分成y行,就需要在n-1个单词间隙中选y-1个位置作为换行点(因为每行至少要有1个单词)。咱们可以用递归的方式来生成所有可能的组合:
function generateAllLineBreaks(array $words, int $lines): array { $result = []; $wordCount = count($words); // 边界情况处理:行数比单词数多,没法合理拆分(可以根据需求调整,比如每行一个单词+空行) if ($lines > $wordCount) { return array_map(fn($word) => [$word], $words); } // 行数等于单词数,只有一种分法:每行一个单词 if ($lines === $wordCount) { return array_map(fn($word) => [$word], $words); } // 递归生成所有分割组合 $generate = function($startIndex, $remainingLines, $currentGroup) use (&$generate, $words, $wordCount, &$result) { // 剩下最后一行时,把剩余所有单词打包进去 if ($remainingLines === 1) { $currentGroup[] = implode(' ', array_slice($words, $startIndex)); $result[] = $currentGroup; return; } // 遍历所有可能的当前行结束位置(要给剩下的行留至少一个单词) for ($i = $startIndex; $i <= $wordCount - $remainingLines; $i++) { $newGroup = $currentGroup; // 把从start到i的单词拼成当前行 $newGroup[] = implode(' ', array_slice($words, $startIndex, $i - $startIndex + 1)); // 递归处理剩下的单词和行数 $generate($i + 1, $remainingLines - 1, $newGroup); } }; $generate(0, $lines, []); return $result; }
比如调用generateAllLineBreaks(["My", "name", "is", "Gary"], 2),会返回三种组合:
[["My", "name is Gary"], ["My name", "is Gary"], ["My name is", "Gary"]]
第三步:筛选出行长差异最小的组合
咱们可以用方差来衡量各行长度的差异(方差越小,整体长度越均匀),然后找出方差最小的组合:
// 计算一组行的长度方差(值越小,长度差异越小) function calculateLineVariance(array $lineGroup): float { $lengths = array_map('strlen', $lineGroup); $average = array_sum($lengths) / count($lengths); $varianceSum = 0; foreach ($lengths as $len) { $varianceSum += pow($len - $average, 2); } return $varianceSum / count($lengths); } // 主函数:整合所有逻辑 function formatLines(string $sentence, int $lines): array { $words = array_filter(explode(' ', trim($sentence))); $allGroups = generateAllLineBreaks($words, $lines); if (empty($allGroups)) { return [$sentence]; // 异常情况直接返回原句 } // 遍历所有组合,找到方差最小的那个 $minVariance = PHP_FLOAT_MAX; $bestGroup = []; foreach ($allGroups as $group) { $currentVariance = calculateLineVariance($group); if ($currentVariance < $minVariance) { $minVariance = $currentVariance; $bestGroup = $group; } } return $bestGroup; }
测试你的例子:formatLines("My name is Gary", 2),会返回["My name", "is Gary"]——因为这两行的长度都是7,方差为0,是最均匀的组合。
内容的提问来源于stack exchange,提问作者Joeseppi
相关产品推荐
相关产品推荐

