PHP实现移除数组中同一数字的所有排列变体
问题分析
原代码无法达到预期的核心原因:
- 数组使用数字索引,但
unset($n[$vs])试图用字符串值作为键删除元素,完全匹配不到目标项 - 遍历过程中没有跳过已被删除的元素,会重复处理无效项
解决方案
步骤1:重构数组结构
将数组转换为「值作为键」的格式,这样可以通过字符串值直接定位元素,方便快速删除操作:
// 保留原数组用于遍历初始元素 $original = $n; // 转换为值做键的数组,键是字符串形式的数字(如"051") $n = array_flip($n);
步骤2:优化遍历与删除逻辑
遍历原数组的每个元素,仅当该元素仍存在于转换后的数组中时,生成其所有排列变体并删除,同时保留当前元素:
foreach ($original as $current) { // 如果当前元素已被删除,直接跳过 if (!isset($n[$current])) { continue; } // 生成当前元素的所有排列变体 $variants = combo($current); // 删除所有变体 foreach ($variants as $v) { if (isset($n[$v])) { unset($n[$v]); } } } // 提取最终保留的原元素 $result = array_keys($n); print_r($result);
步骤3:优化排列生成函数(可选)
原combo函数是硬编码3位数字的排列,对于固定3位场景没问题,但可以改成更通用的全排列生成方式,避免硬编码:
function combo($num) { $chars = str_split($num); $permutations = []; // 递归生成全排列 $generate = function($prefix, $remaining) use (&$generate, &$permutations) { if (empty($remaining)) { $permutations[] = $prefix; return; } for ($i = 0; $i < count($remaining); $i++) { $newPrefix = $prefix . $remaining[$i]; $newRemaining = $remaining; array_splice($newRemaining, $i, 1); $generate($newPrefix, $newRemaining); } }; $generate('', $chars); // 移除原数字本身,只返回变体 $key = array_search($num, $permutations); if ($key !== false) { array_splice($permutations, $key, 1); } return $permutations; }
最终效果
针对示例数组,执行后$result会保留:050, 051, 052, 054, 061, 062, 064,符合预期(移除了501、150、510这些051的排列变体)。
处理镜像变体(如果需要)
如果还需要删除mirror函数生成的镜像值及其排列,可以在删除排列变体后,额外处理镜像:
foreach ($original as $current) { if (!isset($n[$current])) { continue; } // 处理排列变体 $variants = combo($current); foreach ($variants as $v) { if (isset($n[$v])) { unset($n[$v]); } } // 处理镜像值及其排列 $mirrorVal = mirror($current); if (isset($n[$mirrorVal])) { unset($n[$mirrorVal]); $mirrorVariants = combo($mirrorVal); foreach ($mirrorVariants as $mv) { if (isset($n[$mv])) { unset($n[$mv]); } } } }
内容的提问来源于stack exchange,提问作者MrTechie
相关产品推荐
相关产品推荐

