你须要的LeeCode题No.03——“无重复字符的最长子串”_一点课堂(多岸学院)

无重复字符的最长子串

题目:无重复字符的最长子串java

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

示例:数组

  • 输入: "abcabcbb"
  • 输出: 3
  • 解释: 由于无重复字符的最长子串是 "abc",因此其长度为 3。

解析

有了题目001的经验,咱们应该不会再使用暴力搜索方式来解此题。若使用暴力搜索,要获得全部的子字符串,须要双重for循环,时间复杂度为O(n<sup>2</sup>),获得的每一个字符串还须要判断它是否包含重复字符,这一操做也须要O(n)的耗时,从而使得总时间复杂度达到O(n<sup>3</sup>)。这是没法接受的,因此咱们应该寻求更好的解题方式。学习

此题有一个特定条件:无重复字符。若是使用哈希表来存储每一个字符,咱们就能够在构建子串时得知它是否包含重复字符。下面,咱们以示例中的输入"abcabcbb"为例,来讲明哈希表是如何在此问题中发挥做用的。3d

首先,咱们建一个空的哈希表,key值是每一个字符,value是字符的下标。每当遇到一个哈希表中不存在的字符,咱们就把它存入表中,因此咱们能够依次存入'a'->'b'->'c'三个字符,哈希表中的数据以下图:code

file

当咱们要存入第四个字符时,哈希表中已经存在了该字符 'a',也就是说"abca"这个子串中包含了重复字符。如今,咱们能够肯定,以第一个字符 'a' 为起点的最长无重复字符子串就是"abc",且它的长度是 ( 字符 'b' 的下标 - 字符 'a' 的下标 + 1),这个值和哈希表的value正好对应。可是以第二个字符 'b' 为起点的子串有可能比"bca"更长,咱们还须要看下一个字符是否重复,为了保证哈希表中的value值和子串中字符的下标值一致,咱们须要把 'a' 的value更新成 3,也就是后一个 'a' 的下标。以下所示:blog

file

下一个字符是 'b',和上一步状况一致,咱们确认了以第二个字符 'b' 为起点的最长无重复字符子串是"bca",且它的长度是 ( 字符 'a' 的下标 - 字符 'b' 的下标 + 1),可是以第三个字符 'c' 为起点的子串有可能比"cab"更长。重复这个过程,咱们就能够找到以每一个字符为起点的最长无重复字符子串。图片

除了示例的状况,咱们还要考虑第二种状况,好比把输入换成"abcbcad",一开始的结构是一致的,依然是依次存入'a'->'b'->'c'三个字符。当咱们要存入第四个字符时,哈希表中已经存在了该字符'b',可是 'b' 倒是处于中间的字符,这样一来以第一个字符 'a' 为起点的最长无重复字符子串是"abc",以第二个字符 'b' 为起点的最长无重复字符子串是"bc"。而以第三个字符 'c' 为起点的子串,在当前只包含 'c' 和 'b' 两个字符,也就是说字符 'a' 是多余的,以下所示:资源

file

能够考虑把 'a' 从表中删除,但更优雅的方式是使用标记,由于无用字符必定在当前被当作起点的字符以前,因此只要标记好这个字符的位置,就能够忽略无用字符的存在,以下所示:字符串

file

之因此不选择删除字符,是由于没法肯定后续是否还会再次出现这个字符,例如本例中字符 'a' 就会在第6位再次出现,这样咱们以前的删除操做就毫无心义了。

上述过程,咱们只须要对字符串进行一次遍历就能获得结果,时间复杂度仅为O(n),这比暴力搜索好得多。参考代码以下:

public int lengthOfLongestSubstring(String s){
    Map<Character,Integer> map = new HashMap<>();
    int maxLen = 0;
    int startIndex = 0;
    int tempMaxLen = 0;
    for (int i = 0, len = s.length(); i < len; i++) {
        if (map.containsKey(s.charAt(i)) && map.get(s.charAt(i)) >= startIndex) {
            startIndex = map.get(s.charAt(i)) + 1;
        }

        map.put(s.charAt(i), i);
        tempMaxLen = i - startIndex + 1;
        maxLen = maxLen < tempMaxLen ? tempMaxLen : maxLen;
    }
    return maxLen;
}

总结

以上思路也被称做滑动窗口法,这个比喻还挺形象,但愿你们能记住这个思路,当遇到此类问题时可以多往这方面想想,极大可能想到比暴力搜索好得多的算法。

下题预告

题目:寻找两个有序数组的中位数

描述:给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,而且要求算法的时间复杂度为 O(log(m + n))。你能够假设 nums1 和 nums2 不会同时为空。

示例 1:

  • nums1 = [1, 3]
  • nums2 = [2]
  • 则中位数是 2.0

示例 2:

  • nums1 = [1, 2]
  • nums2 = [3, 4]
  • 则中位数是 (2 + 3)/2 = 2.5

相关源码请加QQ获取。


【感谢您能看完,若是可以帮到您,麻烦点个赞~】

更多经验技术欢迎前来共同窗习交流: 一点课堂-为梦想而奋斗的在线学习平台 http://www.yidiankt.com/

![关注公众号,回复“1”免费领取-【java核心知识点】] file

QQ讨论群:616683098

QQ:3184402434

想要深刻学习的同窗们能够加我QQ一块儿学习讨论~还有全套资源分享,经验探讨,等你哦! 在这里插入图片描述

相关文章
相关标签/搜索