无重复字符的最长子串

DESC:

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

示例 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 由英文字母、数字、符号和空格组成

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

CODE1:

JAVA:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int pre=0, afe=0, res=0;
        Map<Character, Integer> map = new HashMap();
        while (pre<n) {
            char c = s.charAt(pre);
            if (map.containsKey(c)) {
                int index = map.get(c);
                afe = Math.max(index, afe);
            }
            res = Math.max(res, pre-afe+1);
            map.put(c, pre+1);
            pre++;
        }
        return res;
    }
}


class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int start=0, res=0;
        Map<Character, Integer> map = new HashMap();
        for (int pre=0;pre<n;pre++) {
            char c = s.charAt(pre);
            if (map.containsKey(c)) {
                start = Math.max(start, map.get(c));
            }
            res = Math.max(res, pre-start+1);
            map.put(c, pre+1);
        }
        return res;
    }
}

NOTE1:

  1. hashmap记录所以字符的位置,为了统一计算长度方便,记录位置索引+1,表示出现重复字符时,从第一个字符下一个位置作为起始位置计算,尾部是第二个重复字符,如[a,..,a]区间,遍历到a出现重复,我们通过(a,..a]、[a+1,..,a]方式计算长度,而非[a,..a)、[a,..,a-1],这里主要是和无重复字符时计算长度公式保持一致,即[aft,pre]=pre-afe+1;
  2. 遍历字符,使用双指针记录起始位置,并计算最大长度,遇到重复字符,获取重复字符开始的位置,与之前的起始位置比较,取最近计算最大长度;如【a,b,..,b,a】遇到第二个a时,起始索引是max(a+1,b+1);

CODE2:

JAVA:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int end=-1, res=0;
        Set<Character> set = new HashSet();
        for (int i=0;i<n;i++) {
            if (i!=0) {
                set.remove(s.charAt(i-1));
            }
            while (end+1<n && !set.contains(s.charAt(end+1))) {
                set.add(s.charAt(end+1));
                end++;
            }
            res = Math.max(res, end-i+1);
        }
        return res;
    }
}
class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int end=0, res=0;
        Set<Character> set = new HashSet();
        for (int i=0;i<n;i++) {
            if (i!=0) {
                set.remove(s.charAt(i-1));
            }
            while (end<n && !set.contains(s.charAt(end))) {//重要,注意end<n条件及end定义位置
                set.add(s.charAt(end));
                end++;
            }
        //res = Math.max(res, end-1-i+1);
            res = Math.max(res, end-i);
        }
        return res;
    }
}

NOTE2:

  1. 滑动窗口思想,遍历求以目前字符为起始字符的最大无重复子串,遍历过程中,移除窗口左边界,右边界继续向右探索,右边界是全局变量,因为窗口内肯定是无重复的;
  2. 难点在于右边界的定义初始化,这里初始化为-1,起始end+1才代表右边界,目的和code一样,统一长度计算公式,兼容无重复字符,[start,end]前闭后闭,因为向右探索中,索引位置为end+1,所以遇到重复字符后,取右边界闭区间位置loc=end+1-1=end;这个地方让人有点迷,还不如code1好想
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值