LeetCode之无重复字符的最长子串超详细java讲解

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

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

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

=================================================================
思路一:暴力求解,依次从左往右,遇到相同的就直接结束,然后从后面一个字符开始,
最后的出最长子串。

    {(a)bcabcbb}(a)bcabcbb 开始的最长字符串为 {(abc)abcbb}(abc)abcbb;
    {a(b)cabcbb}a(b)cabcbb 开始的最长字符串为 {a(bca)bcbb}a(bca)bcbb;
    {ab(c)abcbb}ab(c)abcbb 开始的最长字符串为 {ab(cab)cbb}ab(cab)cbb;
    {abc(a)bcbb}abc(a)bcbb 开始的最长字符串为 {abc(abc)bb}abc(abc)bb;
    {abca(b)cbb}abca(b)cbb 开始的最长字符串为 {abca(bc)bb}abca(bc)bb;
    {abcab(c)bb}abcab(c)bb 开始的最长字符串为 {abcab(cb)b}abcab(cb)b;
    {abcabc(b)b}abcabc(b)b 开始的最长字符串为 {abcabc(b)b}abcabc(b)b;
    {abcabcb(b)}abcabcb(b) 开始的最长字符串为 {abcabcb(b)}abcabcb(b)。

 完整代码如下:

public int lengthOfLongestSubstring(String s){
        int max = 0;
        HashMap<Character,Integer> map = new HashMap<>();
        for(int i = 0;i<s.length();i++){
            int cur = 0;   //每次都要清零整个HashMap表
            map.clear();
            for(int j = i;j<s.length();j++){
                if(map.containsKey(s.charAt(j))){   //遇到相同的则直接跳出循环
                    break;
                }
                map.put(s.charAt(j),j);
                cur++;
            }
            max = Math.max(max,cur);
        }
        return max;
    }

 


=================================================================
思路二:利用滑动窗口:类似于一个队列,比如例题中的 abcav,进入这个窗口为 abc
满足题目要求,当再进入 a队列变成了 abca,这时候不满足要求。所以,我们
要移动这个队列,此时的窗口值为bca即left移动到,b位置,移动到重复值a的后
一位。相当于将与当前相同的值的左边全部移出窗口.
时间复杂度:O(n)
===========================================================================
什么是滑动窗口
滑动窗口算法是在一个特定大小的字符串或数组上进行操作,而不在整个
字符串和数组上操作,这就降低了问题的复杂度,从而也降低了循环的嵌套深度,
滑动窗口主要应用在数组和字符串的场景。
================================================================================
滑动窗口的基本步骤:
需要注意的是:窗口的移动是按照移动的顺序来进行的;窗口的大小不一定是固
定的,可以不断缩小或变大的。

 对于滑动窗口算法的基本解题思路,以字符串S示例如下:

 1.采用双指针来指定窗口的范围,初始化left= right=0,而索引闭区间[left,right]

  便是一个窗口。

 2.不断增大窗口的right指针,直到窗口的字符串满足要求。

 3.此时停止right的增加,转而不断增加left指针,用于缩小窗口[left,right],直到窗

  口中的字符串不在满足要求。每增加一次left,需要更新一次结果。

 4. 重复第2和第3步,直到right到达字符串的尽头。

==============================================================================
完整代码如下:
public int lengthOfLongestSubstring(String s){
        HashMap<Character,Integer> map = new HashMap<>();
        int max = 0;   //最长长度
        int left = 0;  //滑动窗口最初为零
        for(int i = 0;i<s.length();i++){
            if(map.containsKey(s.charAt(i))){      //如果包含,则更新left,
                left = Math.max(left,map.get(s.charAt(i)+1)); //之所以要不能直接取map.get(s.charAt(i))+1是因为当前值可能不包含在有效字段里面
            }
            map.put(s.charAt(i),i);//更新left后,不管原来的 s.charAt(i) 是否在最长子段中,我们都要将 s.charAt(i) 的位置更新为当前的i,
            //如果包含了,则会把之前的给覆盖掉。
            max = Math.max(max,i-left+1);  //更新max
        }
        return max;
    }

 

 

 2021-05-29

posted @ 2021-05-29 22:17  华sam  阅读(1447)  评论(1编辑  收藏  举报