難度: 中等
題目
Given a string, find the length of the longest substring without repeating characters.
給定一個字符串,請你找出其中不含有重復字符的 最長子串 的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
示例 4:
輸入: "dvdf"
輸出: 3
解釋: 因為無重復字符的最長子串是 "vdf",所以其長度為 3。注意不是2。
PHP
暴力解法
1、定義一個方法 isUnique($s, $start, $end) 給定字符串和開始、結束標識,計算里面是否包含重復字符,如果是返回false,否則true。
2、對字符串s遍歷 i*j趟,生成字串使用isUnique判斷是不是重復,如果不是,則更新 返回值 max(最長子串 的長度)。
相當於遍歷 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;
}
/**
* @param String $s
* @return Integer
*/
function lengthOfLongestSubstring($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 ($this->isUnique($s, $i, $j)) {
if ($j - $i + 1 > $max) {
$max = $j - $i + 1;
}
}
}
}
return $max;
}
時間復雜度為O(n^3)。
滑動窗口
上面的暴力解法實在是太慢了。以字符串ababc為例,ab出現了2次,那么對於子串aba、abab、ababc的計算是可以省略的,可以將i直接往后移動。
我們可以使用一個集合(Set)存儲遍歷過的值,如果發現即將要遍歷的字符串已經存在set里,那么可以將i直接往后移動,並將已存在的字符從集合里刪除;如果發現即將要遍歷的字符串不在set里,則放在set里,並將j往后移動,同時更新返回值 max(最長子串 的長度)。
function lengthOfLongestSubstring2($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 {
//出現過,說明符合要求的子字符串已經結束,刪掉子字符串開始的字符
//由於php沒有java的hashSet結構,下面是模擬刪除set里的值
unset($set[array_keys($set, $s[$i++])[0]]);
}
}
return $max;
}
時間復雜度為O(2n)=O(n)。
優化的滑動窗口
function lengthOfLongestSubstring3($s) {
$len = strlen($s);
$max = 0;
$i = $j = 0;
$map = [];
//dvdf
while ($i< $len && $j < $len) {
if (array_key_exists($s[$j], $map)) {
//發現重復字符,key移動到不重復字符的位置
//例如dvdf,第三次發現d,已經重復,第一個的d的索引是0,那么i需要往下移動
$i = max($map[$s[$j]] + 1, $i);
}
$map[$s[$j]] = $j; //key存儲字符,value存儲某個不重復字符的索引
$max = max($max, $j - $i + 1);
$j++;
}
return $max;
}
來源
鏈接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
