3. Longest Substring Without Repeating Characters

3. Longest Substring Without Repeating Characters

题目描述

Given a string, find the length of the longest substring without repeating characters.

Example 1:

Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.
Example 2:

Input: “bbbbb”
Output: 1
Explanation: The answer is “b”, with the length of 1.
Example 3:

Input: “pwwkew”
Output: 3
Explanation: The answer is “wke”, with the length of 3.
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

思路

1,挨个去找出子串,判断里面是否包含重复字符

    /**
     * 计算不包含无重复子串的长度
     * 思路:逐个检查所有的子字符串,看它是否不含有重复的字符
     * 效率低下
     * @param s
     * @return
     */
    public int lengthOfLongestSubString(String s){
        int length = 1;
        if(s == null || s.length()== 0 ){
            return 0;
        }
        if(s.length() == 1){
            return length;
        }

        String maxString = "";
        for(int i = 0; i < s.length(); i++){
            String sub = String.valueOf(s.charAt(i));
            for(int j = i+1; j < s.length(); j++){
                char tempChar = s.charAt(j);
                if(sub.indexOf(tempChar) != -1){
                    //每次跳出循环时候,需要比较当前
                    // 最大的字符串与目前得到的字符串的长度
                    if(maxString.length() < sub.length()){
                        maxString = sub;
                    }
                    break;
                }else{
                    sub += tempChar;
                }
                //每次跳出循环时候,需要比较当前
                // 最大的字符串与目前得到的字符串的长度
                if(maxString.length() < sub.length()){
                    maxString = sub;
                }
            }

        }
        length = maxString.length();
        System.out.println("maxString = [" + maxString + "]");
        return length;
    }

第二个思路,采用滑动窗口的方式,【i, j)在第J个字符时,是否包含,包含的话,则添加进去,否则进行【i+1,j)
详细的思路,可以参见力扣上面的官方说明:
算法

暴力法非常简单,但它太慢了。那么我们该如何优化它呢?

在暴力法中,我们会反复检查一个子字符串是否含有有重复的字符,但这是没有必要的。如果从索引 ii 到 j - 1j−1 之间的子字符串 s_{ij}s
ij

已经被检查为没有重复字符。我们只需要检查 s[j]s[j] 对应的字符是否已经存在于子字符串 s_{ij}s
ij

中。

要检查一个字符是否已经在子字符串中,我们可以检查整个子字符串,这将产生一个复杂度为 O(n^2)O(n
2
) 的算法,但我们可以做得更好。

通过使用 HashSet 作为滑动窗口,我们可以用 O(1)O(1) 的时间来完成对字符是否在当前的子字符串中的检查。

滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)[i,j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)[i,j) 向右滑动 11 个元素,则它将变为 [i+1, j+1)[i+1,j+1)(左闭,右开)。

回到我们的问题,我们使用 HashSet 将字符存储在当前窗口 [i, j)[i,j)(最初 j = ij=i)中。 然后我们向右侧滑动索引 jj,如果它不在 HashSet 中,我们会继续滑动 jj。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 ii 开头。如果我们对所有的 ii 这样做,就可以得到答案。

实现的代码参见如下

    /**
     * 思路:采用滑动窗口的方式来实现
     * @param s
     * @return
     */
    public int lengthOfLongestSubString1(String s){
        int n = s.length();
        SetsubString = new HashSet<>();
        int maxLength =0,i = 0,j =0;
        while( i < n && j < n){
            //【i,j)看看第j个字符是否包含在里面,不包含的话添加进来
            if(!subString.contains(s.charAt(j))){
                subString.add(s.charAt(j++));
                maxLength = Math.max(maxLength,j-i);

            }else{
//                System.out.println("subString = [" + subString.toString() + "]");
                subString.remove(s.charAt(i));
                i++;
            }
        }
        return maxLength;
    }

你可能感兴趣的:(leetcode)