通关剑指 Offer——剑指 Offer II 016. 不含重复字符的最长子字符串

1.题目描述

剑指 Offer II 016. 不含重复字符的最长子字符串

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

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子字符串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子字符串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

示例 4:

输入: s = ""
输出: 0

2.解题思路与代码

2.1 解题思路

这道题使用滑动窗口来进行解答,首先我们定义窗口的左右边界 left 和 right 并都从 0 位置开始,然后让右边界 right 开始在字符串上移动。在移动时,我们需要判断窗口内是否有重复的字符,题目要求字符串由英文字母、数字、符号和空格组成,因此我们可以将字符转换成 asc 码,并使用一个 128 长度的 boolean 型数组 tmp 来记录窗口内字符是否重复,其中字符的 asc 码对应数组的角标,当窗口内存在某个字符的 asc 码时,将对应 asc 码位置上改为 true 表示存在。回到我们窗口右边界 right 上,当窗口内不存在 s.charAt(right) 字符时 tmp 对应位置设置为 true,将右边界向右移动,扩大窗口,直到 right 指向字符在窗口内存在,然后计算此时窗口长度并判断是否为最大。此时我们再固定 right 边界,移动左边界 left 缩小窗口,每移动一次 left 表示 left 所指字符移除窗口,因此将 tmp 中 left 所在位置还原成 false。直到窗口内不再有重复的字符时停止 left 移动,然后继续移动右边界 right,并重复这一步骤。

以字符串 s = "abcabcbb" 为例,我们首先定义一个 tmp 数组和左右边界 left、right。然后首先让 right 在字符串上向右移动,每移动一次就将 tmp 对应位置设置为 true。

当 right 移动到 3 时,此时 tmp[97] (a 的 asc 码为 97)为 true 那么 right 停止移动,开始移动 left 。left 移动到 1 时,0 位置已经离开窗口,那么在 tmp 中 a 字符对应的位置还原为 false。此时 right 指向的 3 位置字符 a 在 tmp中为false,于是继续移动右边界 right 。


重复上面的步骤,直到 right 移动到字符串最后一位为止。

2.2 代码

class Solution {
    public int lengthOfLongestSubstring(String s) {
        boolean[] tmp = new boolean[128];
        int left = 0;
        int right = 0;
        int max = 0;
        while (right < s.length()) {
            while (right < s.length() && !tmp[s.charAt(right)]) {
                tmp[s.charAt(right)] = true;
                right++;
            }
            max = Math.max(max,right-left);
            tmp[s.charAt(left++)] = false;
        }
        return max;
    }
}

2.3 测试结果

通过测试

测试结果

3.总结

  • 使用滑动窗口解答
  • 同时使用一个长度为128的数组记录字符asc码在窗口中是否出现过

你可能感兴趣的:(通关剑指 Offer——剑指 Offer II 016. 不含重复字符的最长子字符串)