题目描述:

给定一个字符串,找出不含有重复字符的最长子串的长度。

示例:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。

给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。

给定 "pwwkew" ,最长子串是 "wke" ,长度是3。请注意答案必须是一个子串,"pwke" 是 子序列  而不是子串。


 

解题过程:

方法一:暴力版本

显然,对于这道题我们可以像以往一样,遍历所有子串,对于这个方法,我相信大家都能想到,我就直接贴代码了。如下

//三个for暴力解决
   public static int lengthOfLongestSubstring(String s) {
       int max = 0;
       int temp = 0;
       char[] arr = new char[s.length()];
       for(int i = 0; i < s.length(); i++){
           arr[i] = s.charAt(i);
           temp = 1;
           for(int j = i + 1; j < s.length(); j++){
               int flag = 0;//用来判断s[j]是否在arr中
               for(int k = i; k < i + temp; k++){
                   if(arr[k] == s.charAt(j)){
                       flag = 1;
                       break;
                   }
               }
               if(flag == 1){ break;//重复
               } else {
                   arr[i+temp] = s.charAt(j);
                   temp++;
               }
           }
           if(temp > max){
               max = temp;
           }
       }
       return max;
   }

前面两个for循环用来遍历所有子串,第三个for循环用来判断字符s.charAt(j)是否在子串中。

方法二:各种优化

优化策略1:大家想一个问题,对于第三个循环,我们在数组里查找该数组是否拥有某个字符,这个查找的过程的时间复杂度是O(n),我们是否有其他什么方法把查找的过程的复杂度降低到O(1)?

前几次我们都有用过hashMap来进行映射,实际上这里一样可以用hashMap来保存子串,然后再判断s.charAt(j)是否子串中,这样我们就可以把查找过程的复杂度降低到O(1)了。

优化策略2:假如给你一个字符串:

"abcdca"

我们在遍历子串的过程中,最开始我们从第一个元素'a'开始遍历,当我们遍历到'abcd'时,在继续查找的时候遇到'c',此时"abcd"里面已经有'c'了,此时该子串查找完毕。此时长度为4,继续下一个子串的查找。

注意:我们继续下一个子串查找的时候,是从第二个元素'b'开始的。可是大家想一个问题,真的有必要从第二个元素'b'开始查找吗?,假如我们从'b'开始的时候,遍历到"bcd",继续遍历时又会再次遇到'c',此时长度为3。比上一个子串4的长度小。

实际上,我们是没有必要从第二个元素开始查找的。我们直接从'd'开始查找就可以了,也就是说,如果 s[j]s[j] 在 [i, j)[i,j) 范围内有与 j'j′ 重复的字符。我们再下一次寻找子串时,直接从j'+1的位置开始就行了。如果你不是很理解为啥会这样的话,可以找一些元素模拟一下勒。

优化策略3:我们每次在寻找子串的时候,会把子串放进hashMap里,假如我们要寻找下一个子串的话,理论上是需要把hashMap里面的元素给清空,然后再用来放置新的子串的。

但实际上,是不需要这样子的,hashMap里面的元素是可以重复利用的。先上代码吧,然后我在画图解释下优化策略三。如下:

//用hashMap映射
   public static int lengthOfLongestSubstring2(String s) {
       int max = 0;//保存最长子串的长度
       //用来记录子串是从哪个下标开始的
       int i = 0;
       Map<Character, Integer> map = new HashMap<>();        for(int j = 0; j < s.length(); j++){
           if(map.containsKey(s.charAt(j))){
               //从第一个重复元素的后一个开始
               i = Math.max(map.get(s.charAt(j))+ 1, i);
           }
           //j - i + 1 表示计算此时子串的长度
           max = Math.max(max, j - i + 1);
           map.put(s.charAt(j), j);
       }
       return max;
   }

假设字符串为"abcba",下面演示hashMap中元素的变化情况。

当j = 2。

当j = 3是,此时出现重复的字符(黄色的表示已经被代替的字符)。

当j = 4时。

j = 4时,hashMap有重复的字符a(下标为0的那个),为啥不会把i定位到下标为2的元素上?(因为它都已经遍历到从下标我为3的那里了,怎么可能还会倒回去)

这种方法的时间复杂度为O(n)。

从零打卡leetcode之day 4--无重复最长字符串的更多相关文章

  1. 从零打卡leetcode之day 2---两数相加

    前言 就是要把leetcode刷完,每天一道题,每天进步一点点. 从零打卡leetcode之day 2 题目描述: 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储, 它们的每个节点只存储单个 ...

  2. 从零打卡leetcode之day 1--两数之和

    前言 就是要把leetcode的题刷完,每天一道题,每天进步一点点 从零打卡leetcode之day 1 题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只 ...

  3. Leetcode(3)无重复字符的最长子串

    Leetcode(3)无重复字符的最长子串 [题目表述]: 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 第一种方法:暴力 执行用时:996 ms: 内存消耗:12.9MB 效果: ...

  4. 【LeetCode题解】3_无重复字符的最长子串(Longest-Substring-Without-Repeating-Characters)

    目录 描述 解法一:暴力枚举法(Time Limit Exceeded) 思路 Java 实现 Python 实现 复杂度分析 解法二:滑动窗口(双指针) 思路 Java 实现 Python 实现 复 ...

  5. leetcode题解#3:无重复字符的最长子串

    leetcode题解:无重复字符的最长子串 题目 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: s = "abcabcbb"输出: 3 解释 ...

  6. Leetcode题库——3.无重复字符的最长子串

    @author: ZZQ @software: PyCharm @file: lengthOfLongestSubstring.py @time: 2018/9/18 20:35 要求:给定一个字符串 ...

  7. leetcode刷题3.无重复字符的最长子串

    题目:给定一个字符串,找出不含有重复字符的 最长子串 的长度. 示例: 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3. ...

  8. LeetCode 第三题--无重复字符的最长子串

    1. 题目 2.题目分析与思路 3.思路 1. 题目 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3 ...

  9. Leetcode(3)-无重复字符的最长子串

    给定一个字符串,找出不含有重复字符的最长子串的长度. 示例: 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3. 给定 &q ...

随机推荐

  1. HFS 轻量化 的文件服务器

    国外的工具 国内的工具

  2. 数据分析 大数据之路 四 numpy 2

    NumPy 数学函数 NumPy 提供了标准的三角函数:sin().cos().tan(import numpy as np a = np.array([0,30,45,60,90])print (' ...

  3. [CF703D]Mishka and Interesting sum/[BZOJ5476]位运算

    [CF703D]Mishka and Interesting sum/[BZOJ5476]位运算 题目大意: 一个长度为\(n(n\le10^6)\)的序列\(A\).\(m(m\le10^6)\)次 ...

  4. Linux内核内存管理架构

    内存管理子系统可能是linux内核中最为复杂的一个子系统,其支持的功能需求众多,如页面映射.页面分配.页面回收.页面交换.冷热页面.紧急页面.页面碎片管理.页面缓存.页面统计等,而且对性能也有很高的要 ...

  5. RSP小组——团队冲刺博客三

    RSP小组--团队冲刺博客三 冲刺日期:2018年12月12日 各成员今日(12.12)完成的任务 马瑞蕃页面布局 李闻洲音乐代码的实现 赵乾宸,找bug,处理bug,使游戏滑动,消除实现 蒋子行会议 ...

  6. Docker容器跨主机通信

    默认情况下Docker容器需要跨主机通信两个主机节点都需要在同一个网段下,这时只要两个Docker容器的宿主机能相互通信并且该容器使用net网络模式,改实现方式为网桥模式通信: 除此之外我们还可以通过 ...

  7. 2017 ES GZ Meetup分享:Data Warehouse with ElasticSearch in Datastory

    以下是我在2017 ES 广州 meetup的分享 ppt:https://elasticsearch.cn/slides/11#page=22 摘要 ES最多使用的场景是搜索和日志分析,然而ES强大 ...

  8. [Educational Round 59][Codeforces 1107G. Vasya and Maximum Profit]

    咸鱼了好久...出来冒个泡_(:з」∠)_ 题目连接:1107G - Vasya and Maximum Profit 题目大意:给出\(n,a\)以及长度为\(n\)的数组\(c_i\)和长度为\( ...

  9. linux操作命令之帮助命令

    一.man命令的帮助: man 命令名 获取指定命令的帮助 例如man ls 查看ls的帮助 man man可以看到man有8个级别的man帮助命令使用场景 1.查看命令的帮助 2.查看可被内核调用的 ...

  10. SpringBoot项目的创建流程(初步)

    小伙伴们在学习的过程中大概也发现了这两个框架需要我们手动配置的地方非常多,不过做JavaEE开发的小伙伴们肯定也听说过“约定大于配置”这样一句话,就是说系统,类库,框架应该假定合理的默认值,而非要求提 ...