https://leetcode-cn.com/problems/longest-substring-without-repeating-characters

一 题目

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

示例 1: 输入: s = “abcabcbb” 输出: 3 解释:

因为无重复字符的最长子串是 “abc”,所以其长度为 3。

示例 2: 输入: s = “bbbbb” 输出: 1 解释:

因为无重复字符的最长子串是 “b”,所以其长度为 1。

示例 3: 输入: s = “pwwkew” 输出: 3 解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。

请注意,你的答案必须是 子串 的长度,”pwke” 是一个子序列,不是子串。

示例 4: 输入: s = “”

输出: 0

提示: 0 <= s.length <= 5 * 104

s 由英文字母、数字、符号和空格组成

二 题解

这题的要求是,字符串的子串是一个没有重复字符的串。
假如:字符串为“acbdbeface”
从头开始找,a->ac->acb->acbd
第一次出现重复:acbdb,重复的字符是b,此时最长字符串长度为 4
因此,下一次查找为:dbe。
很明显了,这就是一个双指针的滑动窗口问题,利用双指针来控制滑动窗口大小,计算窗口的最大值。
没有重复字符的时候,那么子串的长度是在递增的
因此在无重复字符的时候,要计算此时字符串长度是否是当前的最大值。
出现重复字符的时候,那么子串的长度肯定是减小的
因此在出现重复字符的时候,只需要移动子串头部位置到新的位置(即子字符串中哪个位置是与比较的字符重复的)。

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. class Solution {
  4. public int lengthOfLongestSubstring(String s) {
  5. if(s.length()<2){
  6. return s.length();
  7. }
  8. char[] arrays = s.toCharArray();
  9. return doFind(arrays);
  10. }
  11. private int doFind(char[] arrays){
  12. int length = arrays.length;
  13. Map<Character,Integer> map = new HashMap<>();
  14. int start = 0;
  15. int end = 1;
  16. int longestLength = 1;
  17. map.put(arrays[start],start);
  18. while(end<length){
  19. // 判断map中是否存在相同的 字符,并且字符的位置位于两个指针之间
  20. if(map.containsKey(arrays[end])&&(map.get(arrays[end])>=start)){
  21. /*如果为真,则表示在start到end-1之间有字符与end位置的字符是相同的。*/
  22. // 获取到该字符的位置,然后该字符后一位为新的子字符串开始位置
  23. start = map.get(arrays[end])+1;
  24. }else{
  25. /* 如果为假,则表示end位置为非重复的字符因此 */
  26. longestLength = longestLength<(end-start+1)?(end-start+1):longestLength;
  27. }
  28. map.put(arrays[end],end);
  29. end++;
  30. }
  31. return longestLength;
  32. }
  33. public static void main(String[] args) {
  34. Solution solution = new Solution();
  35. String s1 = "abcabcbb";
  36. System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s1));
  37. String s2 = "bbbbb";
  38. System.out.println("预期为1,实际为"+solution.lengthOfLongestSubstring(s2));
  39. String s3 = "pwwkew";
  40. System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s3));
  41. String s4 = "";
  42. System.out.println("预期为0,实际为"+solution.lengthOfLongestSubstring(s4));
  43. }
  44. }

image.png
也可以使用数组来保存出现过的字符与其最后出现的位置

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. class Solution2 {
  4. public int lengthOfLongestSubstring(String s) {
  5. if(s.length()<2){
  6. return s.length();
  7. }
  8. char[] arrays = s.toCharArray();
  9. return doFind(arrays);
  10. }
  11. private int doFind(char[] arrays){
  12. int length = arrays.length;
  13. int[] last = new int[256];
  14. for(int i = 0; i < 256; i++) {
  15. last[i] = -1;
  16. }
  17. int start = 0;
  18. int end = 1;
  19. int longestLength = 1;
  20. last[arrays[start]] = start;
  21. while(end<length){
  22. // 判断该字符串是否出现过,并且出现的位置在start之后
  23. if(last[arrays[end]]>=start){
  24. /*如果为真,则表示在start到end-1之间有字符与end位置的字符是相同的。*/
  25. // 获取到该字符的位置,然后该字符后一位为新的子字符串开始位置
  26. start = last[arrays[end]]+1;
  27. }else{
  28. /* 如果为假,则表示end位置为非重复的字符因此 */
  29. longestLength = longestLength<(end-start+1)?(end-start+1):longestLength;
  30. }
  31. last[arrays[end]] = end;
  32. end++;
  33. }
  34. return longestLength;
  35. }
  36. public static void main(String[] args) {
  37. Solution2 solution = new Solution2();
  38. String s1 = "abcabcbb";
  39. System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s1));
  40. String s2 = "bbbbb";
  41. System.out.println("预期为1,实际为"+solution.lengthOfLongestSubstring(s2));
  42. String s3 = "pwwkew";
  43. System.out.println("预期为3,实际为"+solution.lengthOfLongestSubstring(s3));
  44. String s4 = "";
  45. System.out.println("预期为0,实际为"+solution.lengthOfLongestSubstring(s4));
  46. }
  47. }