给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: "dvdf"
输出: 3
解释: 因为无重复字符的最长子串是 "vdf",所以其长度为 3。注意不是2。
【暴力法】
1、定义一个方法 isUnique($s, $start, $end) 给定字符串和开始、结束标识,计算里面是否包含重复字符,如果是返回false,否则true。
2、对字符串s遍历 i*j趟,生成字串使用isUnique判断是不是重复,如果不是,则更新 返回值 max(最长子串 的长度)。
时间复杂度为O(n^3)
function isUnique($s, $start, $end) { $map = []; $len = $end-$start+1; $sub_str = substr($s, $start, $len); for ($i = 0; $i < $len; $i++) { if (in_array($sub_str[$i], $map) ) { return false; } $map[] = $sub_str[$i]; } return true; } function unRepeat($s) { $len = strlen($s); $max = 0; if ($len > 0) { $max = 1; } for ($i = 0; $i < $len; $i++) { for ($j = $i + 1; $j < $len; $j++) { if (isUnique($s, $i, $j)) { if ($j - $i + 1 > $max) { $max = $j - $i + 1; } } } } return $max; }
【滑动窗口】
上面的暴力解法实在是太慢了。以字符串ababc为例,ab出现了2次,那么对于子串aba、abab、ababc的计算是可以省略的,可以将i直接往后移动。
我们可以使用一个集合(Set)存储遍历过的值,如果发现即将要遍历的字符串已经存在set里,那么可以将i直接往后移动,并将已存在的字符从集合里删除;如果发现即将要遍历的字符串不在set里,则放在set里,并将j往后移动,同时更新返回值 max(最长子串 的长度)。
时间复杂度为O(2n)=O(n)。
function unRepeat($s) { $len = strlen($s); $max = 0; $i = $j = 0; $set = []; while ($i< $len && $j < $len) { if (!in_array($s[$j], $set)) { $set[] = $s[$j++]; $max = max($max, $j - $i); } else { unset($set[array_keys($set, $s[$i++])[0]]); } } return $max; }
优化滑动窗口
function unRepeat($s) { $len = strlen($s); $max = 0; $i = $j = 0; $map = []; while ($i< $len && $j < $len) { if (array_key_exists($s[$j], $map)) { $i = max($map[$s[$j]] + 1, $i); } $map[$s[$j]] = $j; $max = max($max, $j - $i + 1); $j++; } return $max; }
登录后可发表评论
10月13日 16:13