LeetCoed 无重复字符的最长子串(java)

一、题目分析

 

分析:

最长子串,而不是最长子序列。子串是字符串连续的一段,子序列是可以不连续的

所以有一种方法叫做滑动窗口法,我记得左程云老师讲过,那个题是计算窗口内最大或者最小值的

在本题中,窗口一直向右移动,左边缘也可以向右滑动,右边缘也可以,窗口内的字符是不重复的,每一次加入新的值之后都要记录当前窗口的长度。

左右边缘都从begin出发,如果end位置的数已经在窗口中存在,那么左侧边缘向右收缩,直到窗口中无重复

如果没有重复,右侧边缘扩展,并记录窗口大小

 每次在[start,end]中如果有重复的,我们的做法是更新窗口从end重新开始,这种方法要求定义一个hashmap保存字符到索引的映射,并且每次都会更新map的值

下面是一个例子(来自博主 https://www.cnblogs.com/ariel-dreamland/p/8668286.html)

如果给一个例子"abcabcbb",让你手动找无重复字符的子串,该怎么找?一个字符一个字符的遍历,比如a,b,c,然后又出现了一个a,那么此时就应该去掉第一次出现的a,然后继续往后,又出现了一个b,则应该去掉一次出现的b,以此类推,最终发现最长的长度为3。所以说,我们需要记录之前出现过的字符,记录的方式有很多,最常见的是统计字符出现的个数,但是这道题字符出现的位置很重要,所以我们可以使用HashMap来建立字符和其出现位置之间的映射。进一步考虑,由于字符会重复出现,到底是保存所有出现的位置呢,还是只记录一个位置?我们之前手动推导的方法实际上是维护了一个滑动窗口,窗口内的都是没有重复的字符,我们需要尽可能的扩大窗口的大小。由于窗口在不停向右滑动,所以我们只关心每个字符最后出现的位置,并建立映射。窗口的右边界就是当前遍历到的字符的位置,为了求出窗口的大小,我们需要一个变量left来指向滑动窗口的左边界,这样,如果当前遍历到的字符从未出现过,那么直接扩大右边界,如果之前出现过,那么就分两种情况,在或不在滑动窗口内,如果不在滑动窗口内,那么就没事,当前字符可以加进来,如果在的话,就需要先在滑动窗口内去掉这个已经出现过的字符了,去掉的方法并不需要将左边界left一位一位向右遍历查找,由于我们的HashMap已经保存了该重复字符最后出现的位置,所以直接移动left指针就可以了。我们维护一个结果res,每次用出现过的窗口大小来更新结果res,就可以得到最终结果了。

二、java代码

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int res = 0;//记录最长子串的长度
        int end=0,start=0;//记录开始和结尾的下标
        Set<Character> set=new HashSet<>();//使用set容器不重复
        while(start<n && end<n){
           if(set.contains(s.charAt(end))){//如果窗口右侧的字符已经存在
               set.remove(s.charAt(start++));//左侧窗口边界向右
           }else{
               set.add(s.charAt(end++));//如果窗口中无重复,窗口右侧向右滑动
               res=Math.max(res,end-start);//同时记录当前最大长度
           }           
        }
        return res;
 }
}

理解hashset和使用 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章