滑动窗口算法

Sliding window

Posted by HaoDu on April 23, 2020

题目

leetcode 0003 题 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

1
2
3
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

1
2
3
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

1
2
3
4
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

思路:

1暴力解法 时间复杂度 O(n²)

//看到这道题就想到了按照冒泡排序类似算法,两个 for循环找出,时间复杂度 O(n²);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function lengthOfLongestSubstring($s)
{
    $count = strlen($s);
    //只有一个字符或空的字符串特殊处理
    if ($count == 1||$count == 0) {
        return $count;
    }
    $longestLen = 0;//最长长度
    $list = str_split($s);

    //当剩余循环长度>已统计子串长度时,循环进行
    for ($i = 0; $i < $count - $longestLen; $i++) {
        $subList = [];//清空子串数组
        for ($j = $i; $j < $count; $j++) {
            if (!in_array($list[$j], $subList, true)) {//注意加第三个参数 true 否则是松散比较,会自动类型转换,' ' == 0
                $subList [] = $list[$j];
            } else {//遇到重复字符时,更新最长长度且终止本次循环
                break;
            };

        }
        $subCount = count($subList);
        $longestLen = max($longestLen, $subCount);
    }
    return $longestLen;
}
//var_dump(lengthOfLongestSubstring($s));

2 滑动窗口 时间复杂度 O(n)

这道题主要用到思路是:滑动窗口 什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

时间复杂度:O(n);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$s = 'abcabcad';
function lengthOfLongestSubstring1($s)
{
    $count = strlen($s);
    //只有一个字符或空的字符串特殊处理
    if ($count == 1 || $count == 0) {
        return $count;
    }
    $longestLen = 0;//最长长度
    $list = str_split($s);
    $subList = [];//初始化子串数组
    for ($i = 0; $i < $count; $i++) {
        if (in_array($list[$i], $subList, true)) {//注意加第三个参数 true 否则是松散比较,会自动类型转换,' ' == 0
            //遇到重复字符时,滑动
            $key = array_search($list[$i], $subList);
            $subList = array_slice($subList, $key + 1);//算出"滑动"距离
        };
        $subList [] = $list[$i];//滑动后展现新内容
        $longestLen = max($longestLen, count($subList));
    }
    return $longestLen;
}
var_dump(lengthOfLongestSubstring1($s));

2.1 直接用字符串好像更快些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//一开始就陷入误区...用了数组
function lengthOfLongestSubstring($s) {
    $len = strlen($s);
    $max = 0;
    $temp = '';
    for($i = 0;$i < $len;$i++){
        $live = strpos($temp,$s[$i]);
        if($live !== false){
            $temp .=$s[$i];
            $temp = substr($temp,$live+1);
        }else{
            $temp .=$s[$i];
        }
        $max = max(strlen($temp),$max);
    }
    return $max;
}