PHP中找最长无重复子串需用滑动窗口+哈希表,时间复杂度O(n),UTF-8字符串需先用preg_match_all('/./u')拆分为字符数组再处理。

要找出 PHP 字符串中最长的无重复字符子串,核心是用滑动窗口(双指针)配合哈希表记录字符最近出现位置,时间复杂度 O(n),空间复杂度 O(min(m,n))(m 为字符集大小)。
滑动窗口 + 关联数组记录位置
维护左指针 $left 和右指针 $right,遍历字符串时用关联数组(如 $seen)存每个字符最后一次出现的索引。当 $s[$right] 已存在且其位置 ≥ $left,说明窗口内出现重复,就把 $left 移到该字符上次位置的下一位。
- 每次更新前计算当前窗口长度:$right - $left + 1
- 只在窗口有效(无重复)时更新最大长度和对应子串
- 注意 PHP 中字符串支持下标访问(如 $s[3]),但需确保是单字节编码;若含 UTF-8 多字节字符,应先用 mb_substr() 等函数处理
简单可运行示例
以下代码适用于 ASCII 或单字节字符串:
function lengthOfLongestSubstring($s) {
$n = strlen($s);
if ($n === 0) return 0;
<pre class='brush:php;toolbar:false;'>$left = 0;
$maxLength = 0;
$start = 0; // 记录最长子串起始位置
$seen = [];
for ($right = 0; $right < $n; $right++) {
$char = $s[$right];
if (isset($seen[$char]) && $seen[$char] >= $left) {
$left = $seen[$char] + 1;
}
$seen[$char] = $right;
$len = $right - $left + 1;
if ($len > $maxLength) {
$maxLength = $len;
$start = $left;
}
}
return ['length' => $maxLength, 'substring' => substr($s, $start, $maxLength)];} // 示例:print_r(lengthOfLongestSubstring("abcabcbb")); // ['length'=youjiankuohaophpcn3, 'substring'=>"abc"]
UTF-8 字符串需额外处理
PHP 默认按字节操作字符串,对中文、emoji 等多字节字符会出错。解决方法:
立即学习“PHP免费学习笔记(深入)”;
- 先用 preg_match_all('/./u', $s, $matches) 将字符串拆成 Unicode 字符数组
- 后续逻辑不变,但遍历的是 $matches[0] 数组,索引对应字符位置
- 拼接结果时用 implode('', array_slice($matches[0], $start, $maxLength))
边界情况注意点
空字符串、单字符、全相同字符、全不同字符都应正确返回:
- 空串 → 返回 0 和空字符串
- "a" → 返回 1 和 "a"
- "aaaa" → 返回 1 和 "a"
- "abcdef" → 返回 6 和原串
- 包含空格、数字、符号(如 "ab c!d")也正常处理,只要它们是独立字符











