其他分享
首页 > 其他分享> > LeetCode 3:Longest Substring Without Repeating Charact

LeetCode 3:Longest Substring Without Repeating Charact

作者:互联网

LeetCode 3:Longest Substring Without Repeating Charact

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

说人话:

在一个字符串中寻找没有重复字母的最长子串。

举例1:

image-20210122163355086

举例2:

image-20210122163408215

举例3:

image-20210122163430619

举例4:

image-20210122163443578

[法1] 滑动窗口

思路

滑动窗口的思想是我们取 2 个索引 ij ,这样就围成了一个窗口,窗口 s[i…j] 是没有重复字母的。

image-20210122171447843

① 然后我们不断向右边扩展,直至字符串结束或者是遇到重复字符了。那么这个时候我们就暂时找到了一个符合条件的子串的,记下当前的子串长度。

image-20210122171612174

② 然后我们从左边删除字符,直至字符串不包含即将从右边加入的字符的时候就停下。

image-20210122171716520

这样我们就又可以执行 ① 来扩展子串了,这个循环 ① ② 直至结束。

算法
class Solution {
    public int lengthOfLongestSubstring(String s) {

        int result = 0;

        //子串为 s[left...right]
        int left = 0;
        int right = -1;

        while(left < s.length()){

            //不断往后边加入满足条件的字符
            while(right+1 < s.length() &&
             !s.substring(left,right+1).contains(s.substring(right+1,right+2))){ 
                right++;
            }

            //跳出循环,记录当前最长的子串长度
            result = (result > (right-left+1))?result:(right-left+1);

            //右边已经到底了,那就说明已经找到最长的了
            if(right == s.length()-1){
                break;
            }

            //不能往后边加的时候,从左边删,删到可以往后边加为止
            while(left < s.length() &&
                    s.substring(left,right+1).contains(s.substring(right+1,right+2))){
                left++;
            }
        }
        return result;
    }
}
提交结果
image-20210122171342040
代码分析
改进思路

为什么 O(n) 的时间复杂度在 Leetcode 提交后执行用时这么久呢?其实是因为我们在判断字符串中是否存在某字符的时候用了 JDK 的 API:s.contains(substring)。这个 API 在判断的时候每次都会遍历我们整个字符串,这是比较耗时的,也是我们可以改进的地方。

[法2] 优化判断是否重复的逻辑

思路

ASCII 总共就 256 个,我们可以创建一个临时数组来记录字符串中的字符在 ASCII 中出现的频率,以此来判断是否存在重复字符。

代码
class Solution {
    public int lengthOfLongestSubstring(String s) {

        //记录字符出现频率
        int[] freq = new int[256];

        int result = 0;

        //子串为 s[left...right]
        int left = 0;
        int right = -1;

        while(left < s.length()){

            //不断往后边加入满足条件的字符
            while(right+1 < s.length() && freq[s.charAt(right+1)] == 0){
                right++;
                freq[s.charAt(right)] ++;
            }

            //跳出循环,记录当前最长的子串长度
            result = (result > (right-left+1))?result:(right-left+1);

            //右边已经到底了,那就说明已经找到最长的了
            if(right == s.length()-1){
                break;
            }

            //不能往后边加的时候,从左边删,删到可以往后边加为止
            while(left < s.length() && freq[s.charAt(right+1)] > 0){
                freq[s.charAt(left)] --;
                left++;
            }
        }

        return result;

    }
}
提交结果
image-20210122173908727
代码分析

标签:字符,right,int,Charact,Substring,length,Without,result,left
来源: https://blog.51cto.com/u_15298624/3035446