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

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

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

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

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


今天刷题碰到这个题目,把这个题目的解题思路跟大家分享一下
分析:看到这个题目时,首先会想到去遍历这个字符串

  1. 当遍历一个新的字符时需要知道是否已经出现过
  2. 若出现过就得计算当前遍历的子字符的长度,记录下这个长度。
  3. 若没有出现过,则继续遍历,重复 1 2 3知道遍历结束。

这里有两个重要的难点:当出现重复字符时如何计算字符长度?如何知道遍历的新字符是否出现过,并且出现的位置在哪里?
解决以上两个问题:

  1. 我们定义一个变量startIndex记录子串的起始位置,用当前的遍历的下标(i)减去字符串开始下标(startIndex)就是子串的长度
  2. 我们需要定义一个义ASCII码值为下标的一个数组,初始化为全-1,代表该字符未出现过
    int[] ascii = new int[128];
    ascii[0] = -1;…ascii[127]=-1;
    遍历字符时,根据字符拿到数组对应的值如果为-1,说明该字符未出现,若不是-1,说明可能出现过,这里为什么说可能出现过呢?因为当我们碰到以当前字符为下标的ASCII数组的值(也就是字符的下标)出现在startIndex的左边,是上一个子字符串出现的对于当前的字符串是无效的。当大于startIndex我们得计算出子串的值,用当前的遍历的下标(i)减去字符串开始下标(startIndex)

看下面一个例子:字符串“gfababfmpo”
g f a b a b f
startIndex: 0 0 0 0 0 3 5
ASCII码: 0 1 2 3 重复 重复
子符串长度: 4
最长度子字符串: 4
当遍历第2个a时,a的下标不是-1,说明重复,计算子字符串长度4-startIndex = 4-0 = 4,更新startIndex = 2+1 = 3,按对应下标更新为4
接下来遍历第2个b,b下标的不是-1,说明重复,计算子字符串长度5-3 =2,不更新最长子字符串。更新startIndex为b下标对应值+1=3+1=4 ,更新b下标的值为5
接下来遍历第二个f,f 下标值不是-1,但是不是已经出现,因为出现startIndex的左边,虽然已经出现过了,但是对于当前的子字符串没有关系,因此当不是-1还要判断是否大于等于startIndex,当两个条件都满足,说明字符重复出现。下面给出代码

public class Solution {
    public static void main(String[] args) {
        System.out.println(new Solution().lengthOfLongestSubstring("abcabcbb"));
    }

    public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() <= 0) return 0;
        if (s.length() == 1) return 1;
        int[] ascii = new int[128];
        //初始化数组为全-1
        initArr(ascii);
        int startIndex = 0;
        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            if (ascii[s.charAt(i)] != -1) {
                if (ascii[s.charAt(i)] >= startIndex) {
                    //计算当前子串的长度
                    int len = (i - startIndex);
                    if (len > max) max = len;
                    //重新记录起始下标
                    startIndex = ascii[s.charAt(i)] + 1;
                }
            }
            ascii[s.charAt(i)] = i;
        }
        if (max < (s.length() - startIndex)) max = s.length() - startIndex;
        return max;
    }

    private void initArr(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = -1;
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值