算法练习:无重复字符串的最长子串(有点难)

无重复字符串的最长子串(有点难)

题目链接:无重复字符串的最长子串

题干内容:

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

  • 示例一:

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

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

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

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

尝试解法(请跳过):

public int lengthOfLongestSubstring(String s){
        int max = 0;
        for (int i = 0; i < s.length(); i++) {
            String str = s.substring(i);
            max = Math.max(max , getNum(str));
        }
        return max;
    }

    public int getNum(String s) {
        int time = 0;
        int length = 0;
        char[] chars = s.toCharArray();
        if (s.length() == 1){
            return 1;
        }else if (s.length() == 0){
            return 0;
        }
        for (int i = 0; i < chars.length; i++) {
            String s1 = s.substring(0,i);
            length = i;
            if ( s1.contains(chars[i]+"") ){
                time++; //表示有重复字符串
                //System.out.println(i+"______"+s.substring(i+1));
                int temp = lengthOfLongestSubstring( s.substring(i) );
                if (temp > length){
                    length = temp;
                    System.out.println("交换:"+temp);
                }
                break;
            }
        }
        //System.out.println("返回:"+length);
        return time==0 ? length+1 : length;
    }

在这里插入图片描述

直接超出时间限制,简单来说,就是时间复杂度太大,代码写得太垃圾了。

简单思路:

  1. 设置一个变量length记录当前最长子串的长度;两个变量i,j分别记录下标位置。

    String str = "abcdcabed"int length = 0;
    int i,j = 0;
    
  2. 从首字符开始遍历,每遍历一个不相等字符使length++,j++,i不变;(即:记录每一次遍历后的最长长度。)

  3. 直到遇见已经遇见过的字符比如字符’c’,则从已遍历的字符中寻找下标最大的那个’c’;

    "abcdcabed"   j指向第二个'c',j=4 ,i=0不变
    
    此时length = 4,j=4;因为遍历到第二个字符'c'时,因为已存在,所以length不加,所以length = 4为目前的最长长度
    
  4. 以此字符’c’为临界点拆分原来的字符串,以此字符’c’之后的字符串为新的字符串,i指向此字符’c’之后的字符。

    "abcdcabed"
    拆分后:"abc"  "dcabed"
    j仍指向第二'c':j=4;   i指向第一个'c'后面的字符'd', i=3
  5. 计算新的长度length,与之前的length相比较取大的数。

    "dcabed"   依次为新的字符串来看,相当于j的第二次"j++";
    所以新length = j-i+1=2; 
    
  6. 循环步骤2,直至遍历完整个原字符串。

解法一

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length()int length = 0;
        Map<Character, Integer> map = new HashMap<>(); 
        for (int j = 0, i = 0; j < n; j++) {
            //有重复则移动i的下标
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i); 
            }
            length = Math.max(ans, j - i + 1);//设置新长度
            map.put(s.charAt(j), j + 1);//key值为记录字符,value记录当前字符下角标的后一位,用来更改i节点
        }
        return length;
    }
}
  • 时间复杂度:O(n)。

  • 空间复杂度:O(min(m,n))。

  • 执行用时:4 ms, 在所有 Java 提交中击败了86.62%的用户

  • 内存消耗:41.2 MB, 在所有 Java 提交中击败了67.41%的用户

    通过测试用例:987 / 987

解法二

将每次读取的字符的 “下标+1" 存到整型数组index中去(以字符对应的ASCLL码值为下标)

缺点是只是用字符串长度不那么大的字符串。

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), length = 0;
        int[] index = new int[128];   
        for (int j = 0, i = 0; j < n; j++) {
            
            //自动判断了是否遇见已存在的字符,
            //因为若字符已存在,则index[s.charAt(j)]返回对应i变化后的下标;
            //若字符不存在,则index[s.charAt(j)]本身就是0。
            i = Math.max(index[s.charAt(j)], i);
            length = Math.max(length, j - i + 1);
            index[s.charAt(j)] = j + 1;  //将对应i的下标存到以字符ASCLL值为下标的位置去
        }
        return length;
    }
}

时间复杂度:O(n)。

空间复杂度:O(m),m 代表字符集的大小。这次不论原字符串多小,都会利用这么大的空间。

执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:41.2 MB, 在所有 Java 提交中击败了64.24%的用户

通过测试用例:987 / 987

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值