Day3 无重复字符的最长子串

作者: Shimmer_ | 来源:发表于2021-01-28 13:37 被阅读0次

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

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

示例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 * 10^4

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

Java算法

思路:

  1. 先将问题拆分为 字符串拆分排列组合,以及字符串自身查重,
  2. 尝试运行后,发现计算超时,这里是暴力穷举
  • 优化思路
    • 无重复字符串最长,在找到相同长度时不再继续,转向更大位数查找
    • 官方解更NICE
package sj.shimmer.algorithm;

import java.util.HashSet;
import java.util.Set;

/**
 * Created by SJ on 2021/1/27.
 */

class D3 {
    public static void main(String[] args) {
        System.out.println(lengthOfLongestSubstring("abcabcbb"));
        System.out.println(lengthOfLongestSubstring("bbbbb"));
        System.out.println(lengthOfLongestSubstring("pwwkew"));
        System.out.println(lengthOfLongestSubstring(""));

    }
    public static int lengthOfLongestSubstring(String string) {
        if (string==null||string.length()==0) {
            return 0;
        }
        int length = 1;
        return Math.max(length,getCombination(string, 2));
    }
    public static int getCombination(String string, int sLength) {
        if (string==null||string.length()<sLength) {
            return 0;
        }
        for (int i = 0; i < string.length(); i++) {
            int sub = sLength + i;
            if (sub >string.length()) {
                break;
            }
            String substring = string.substring(i, sub);
            if (!hasRepait(substring)) {
                return Math.max(sLength,getCombination(string,++sLength));
            }
        }
        return 0;
    }
    public static boolean hasRepait(String string){
        Set<Character> set = new HashSet();
        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            if (set.contains(c)) {
                return true;
            }
            set.add(c);
        }
        return false;
    }
}
image

官方解

滑动窗口

在字符串中查找子串,相当于该子串的左右边界在字符串中根据条件滑动,来查找,类似与滑动窗口一样

左右指针遍历一次列表,省去大量循环

  • 左边界 k,右边界k,右边界每轮中不停右移,左边界在停止或完成轮询时,右移

  • 从第k个字符串开始查找,每次查找都将 字符添加至hashset,若移动到j+1有重复时表示找到了以k,j为始终位置的最长字符,就可以停止此轮遍历

  • 下一轮则以k+1开始
    以k+1开始时,k,j 不重复,k+1,j自然也不重复,所以只需从set中移除掉k位置的char即可,右边界则以j为开始移动

  • 。。。

  • 每轮记录比较最大值,即可得出

    优点:相比较省去大量重复计算,时空优化很高,左右指针只遍历一次

    时间复杂度:O(N),其中 N 是字符串的长度。左指针和右指针分别会遍历整个字符串一次。

    空间复杂度:O(∣Σ∣),其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。

public int lengthOfLongestSubstring(String s) {
    Set<Character> set = new HashSet<>(); // 哈希集合,用于判重
    int length = s.length();
    // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
    int rightIndex = -1, resultLength = 0;
    for (int i = 0; i < length; ++i) {
        if (i != 0) {
            set.remove(s.charAt(i - 1));// 左指针向右移动一格,移除一个字符;避免影响后续查重
        }
        while (rightIndex + 1 < length && !set.contains(s.charAt(rightIndex + 1))) {
            // 不断地移动右指针
            set.add(s.charAt(rightIndex + 1));
            ++rightIndex;
        }
        // rightIndex - i + 1为当前轮找到的最长长度(i为左指针)
        resultLength = Math.max(resultLength, rightIndex - i + 1);
    }
    return resultLength;
}

相关文章

网友评论

    本文标题:Day3 无重复字符的最长子串

    本文链接:https://www.haomeiwen.com/subject/glwttltx.html