PHP中如何将关联数组作为另一关联数组的键(类比Java HashMap)
高效解决PHP中字母异位词分组问题
问题核心
现有字母异位词分组方案依赖ksort排序字符频率数组+serialize序列化作为键,大数据场景下性能衰减明显。需要找到无需排序、序列化的高效实现,类比Java中用HashMap作为键的思路。
方案1:固定顺序字符计数键(最优通用方案)
利用异位词的字符计数完全一致的特性,按a-z固定顺序统计每个字符出现次数,再拼接成结构化字符串作为分组键,天然避免排序和序列化的开销。
function groupAnagrams(array $strs) { $groups = []; foreach ($strs as $str) { // 初始化26位数组,对应a-z的计数,默认0 $charCount = array_fill(0, 26, 0); $strLen = strlen($str); for ($i = 0; $i < $strLen; $i++) { // 计算字符对应的索引:a对应0,b对应1... $index = ord($str[$i]) - ord('a'); $charCount[$index]++; } // 拼接成类似"1:0:2:0..."的字符串作为唯一键 $key = implode(':', $charCount); $groups[$key][] = $str; } return array_values($groups); }
优势
- 无需排序:按a-z固定顺序统计,天然保证相同异位词的键一致
- 替代序列化:用
implode简单拼接数字,比serialize处理复杂数组结构的性能提升显著 - 时间复杂度O(n*k)(n为字符串数量,k为单字符串最大长度),与原方案一致但常数项开销更小
方案2:质数乘积哈希法(短字符串场景最优)
利用质数乘积的唯一性:给每个字母分配唯一质数,将字符串中所有字符对应的质数相乘,乘积作为分组键。异位词的乘积必然相同。
function groupAnagrams(array $strs) { // 给a-z分配26个不重复的质数 $primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]; $groups = []; foreach ($strs as $str) { $hash = 1; $strLen = strlen($str); for ($i = 0; $i < $strLen; $i++) { $index = ord($str[$i]) - ord('a'); $hash *= $primes[$index]; } $groups[$hash][] = $str; } return array_values($groups); }
注意事项
- 长字符串可能导致乘积超出PHP整数范围,转为浮点数后会丢失精度,引发哈希冲突,仅适合短字符串场景
- 纯数值计算,无字符串操作,性能极优(短字符串下)
为什么spl_object_hash/SplObjectStorage无效?
PHP中,即使两个对象的属性完全一致,它们也是不同的实例:
spl_object_hash返回的是对象实例的唯一标识,而非属性内容的哈希SplObjectStorage基于对象实例存储,无法识别属性相同的不同对象,因此不适用于该场景
原方案性能瓶颈分析
ksort:循环中多次对关联数组排序,即使字符数量最多26,累积开销仍不可忽视serialize:序列化关联数组需要处理键值结构,生成的字符串较长,哈希表键处理开销大
内容的提问来源于stack exchange,提问作者habib
相关产品推荐
相关产品推荐

