leetcode解题之无重复字符的最长子串

本文探讨了解决LeetCode上最长无重复字符子串问题的多种方法,从暴力解法到滑动窗口优化,逐步提升算法效率。通过具体示例,详细分析了不同解法的优缺点及实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

示例 1:

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

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

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

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

第一时间想到的是列出给定字符串的所有子串,然后找出所有子串中无重复字符中的最长的,根据这一思路写出如下代码:

public class Solution3 {
    public int lengthOfLongestSubstring(String s) {
        int len=0;
        String childStr="";
        //将所有的可能的连续子串列出
        ArrayList ls = new ArrayList();
        for(int i=0;i<s.length();i++){
           for (int j=i+1;j<s.length();j++){
            String tem = s.substring(i,j);
            ls.add(tem);
           }
        }
 for (int i=0;i<ls.size();i++){
            String cs = ls.get(i).toString();
//            System.out.println(cs);
            if (!isHasSameStr(cs)&&len<cs.length()){
                len=cs.length();
                childStr=cs;
            }
        }
        System.out.println("最长子串:"+childStr);
        System.out.println("最长子串长度:"+len);
        return len;
    }
    //使用set集合判断是否有重复字符
    public boolean isHasSameStr(String s){
        Set set = new HashSet();
        String[] ls = s.split("");
        for (int i=0;i<ls.length;i++){
            set.add(ls[i]);
        }
        if (set.size()<s.length()){
            return true;
        }
       return false;
    }
}

执行通过,但是很遗憾,当s=" "时,结果为0,错误了,然后查代码,发现是substring边界的问题,其第二个参数为截取结束的位置但不包括,更改上述代码:

public class Solution3 {
    public int lengthOfLongestSubstring(String s) {
        int len=0;
        String childStr="";
        //将所有的可能的连续子串列出
        ArrayList ls = new ArrayList();
        for(int i=0;i<s.length();i++){
           for (int j=i+1;j<=s.length();j++){
            String tem = s.substring(i,j);
            ls.add(tem);
           }
        }
 for (int i=0;i<ls.size();i++){
            String cs = ls.get(i).toString();
//            System.out.println(cs);
            if (!isHasSameStr(cs)&&len<cs.length()){
                len=cs.length();
                childStr=cs;
            }
        }
        System.out.println("最长子串:"+childStr);
        System.out.println("最长子串长度:"+len);
        return len;
    }
    //使用set集合判断是否有重复字符
    public boolean isHasSameStr(String s){
        Set set = new HashSet();
        String[] ls = s.split("");
        for (int i=0;i<ls.length;i++){
            set.add(ls[i]);
        }
        if (set.size()<s.length()){
            return true;
        }
       return false;
    }
}

提交,悲剧的是超时了,让后想着减少执行时间,想的是在列出子串的地方做文章,在二层循环的时候,只要子串中出现重复的字符,那么之后的子串就没必要列出来了,再次修改代码:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class Solution3 {
    public int lengthOfLongestSubstring(String s) {
        int len=0;
        String childStr="";
        int step=1;
        //将所有的可能的连续子串列出
        ArrayList ls = new ArrayList();
        for(int i=0;i<s.length();i++){
           for (int j=i+step;j<=s.length();j++){
            String tem = s.substring(i,j);
            if (isHasSameStr(tem)){
               if (step<tem.length()-1){
                   step=tem.length()-1;
               }
                break;
            }else{
                if (len<tem.length()){
                    len=tem.length();
                    childStr=tem;
                }
            }
           }
        }
     
        System.out.println("最长子串:"+childStr);
        System.out.println("最长子串长度:"+len);
        return len;
    }
    //使用set集合判断是否有重复字符
    public boolean isHasSameStr(String s){
        Set set = new HashSet();
        String[] ls = s.split("");
        for (int i=0;i<ls.length;i++){
            set.add(ls[i]);
        }
        if (set.size()<s.length()){
            return true;
        }
       return false;
    }

    public static void main(String[] args) {
        Solution3 s3 = new Solution3();
        String s="avvhrxyhbeplapvwncwydwgypimhmnwmksvcpulsyadapbwfdsdjqmhfutmgilutdqxumimmlrmauifyalhqxq";
        s3.lengthOfLongestSubstring(s);
    }
}

提交勉强通过。
官方题解
暴力解法都比我的要简练,还需要努力啊。第三种方法看的有点晕。

补充滑动窗口的解法,主要原理是从第一个字符开始往hash表中放,已存在则将其从hash表中删除,外层循环+1,开始从下一个字符开始计算长度,循环往复

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //滑动窗口
        int len = s.length();
        Set<Character> set = new HashSet<>();//保存无重复的字符
        int right = -1;
        int ans=0;
        for(int i=0;i<len;i++){
            if(i!=0){
                set.remove(s.charAt(i-1));
            }
          while(right+1<len&&!set.contains(s.charAt(right+1))){
                set.add(s.charAt(right+1));
                right++;
            }
            ans=Math.max(ans,right-i+1);
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值