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

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

法一:

 1 public class Solution {
 2     public int lengthOfLongestSubstring(String s) {
 3         int ans = 0;
 4         HashMap<Character,Integer> map = new HashMap<>();
 5         for(int i = 0 ,j = 0 ;j < s.length(); j++ ){
 6             if(map.containsKey(s.charAt(j))){
 7                 i = Math.max(map.get(s.charAt(j)) + 1 , i);
 8             }
 9             map.put(s.charAt(j),j);
10             ans = Math.max(ans, j - i + 1);
11         }
12         return ans;
13     }
14 }

i为起始窗口start,j为终点窗口end,利用滑窗思想,map中存放每一个字母和其最后出现的序列号,当end出现重复字母,即将start更新到map中该重复字母的下一位。

如果end字母不在map中,则存入map,记录序列号;

如果end字母在map中,则更新start,滑动起始窗口,(需注意,要比较原start序列号和重复字母序列号,不能直接更新start,防止指针回跳,例如cabac,当a重复,start更新到b处,接着end滑到c时,map中c位序为0,但c已经不再滑动窗口中,不能更新start,否则造成指针start回跳到c处)再更新map中重复字母位序

最后比较当前子串和记录最长子串大小

 

法二:

 1 public class Solution2 {
 2     public int lengthOfLongestSubstring(String s) {
 3         HashSet<Character> set = new HashSet<>();
 4         int i = 0, j = 0, ans = 0;
 5         while( j < s.length()){
 6             if(set.contains(s.charAt(j))) {
 7                 set.remove(s.charAt(i));
 8                 i++;
 9             }else {
10                 set.add(s.charAt(j));
11                 ans = Math.max(ans, j - i + 1);
12                 j++;
13             }
14         }
15         return ans;
16     }
17 }

利用HashSet记录不重复字母,当出现重复字母时,按照start的后移顺序,依次剔除,直至删除到end重复字母,保持set中始终为当前end字母情况下的最短不重复子串,最后更新ans为最大值

 

法三:

 1 class Solution3 {
 2     public int lengthOfLongestSubstring(String s) {
 3         char[] charArr = s.toCharArray();
 4         if (charArr.length == 0) {
 5             return 0;
 6         }
 7         int maxLength = 0;
 8         int baseIndex = 0;
 9         int i;
10 
11         //i从第二个元素开始
12         for (i = baseIndex + 1; i < charArr.length; i++) {
13 
14             //j从base开始,从前往后找,与第i个相同的元素,并且计算长度
15             for (int j = baseIndex; j < i; j++) {
16 
17                 //如果找到相同元素,base直接跳到当前元素下一个
18                 if (charArr[j] == charArr[i]) {
19                     maxLength = (i - baseIndex) > maxLength ? (i - baseIndex) : maxLength;
20                     baseIndex = j + 1;
21                     break;
22                 }
23             }
24         }
25 
26         //全部遍历后还要再计算一次,如果直到最后一位还没有重复元素的情况
27         maxLength = (i - baseIndex) > maxLength ? (i - baseIndex) : maxLength;
28         return maxLength;
29     }
30 }

将字符串转为字符数组,利用双脚标ij,起始脚标baseIndex,当i每次后移一位,j从baseIndex开始后移直至找到与arr[i]相同字母,则i-baseIndex为该次最长不重复子串,更新baseIndex,再次移动i,直至结束。

例如cabae,当arr[1]=arr[3]=a时,去掉arr[3],cab即为最长不重复子串,更新baseIndex = j + 1。

posted @ 2020-06-26 19:57  陈糊糊啊  阅读(130)  评论(0)    收藏  举报