面试热题(无重复字符的最长子串)

无重复字符的最长子串

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

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

解法一:

    public int lengthOfLongestSubstring(String s) {
      if(s==null){
          return 0;
      }
      int max=0;
      //因为s中包含数字、英文、符号,所以设置长度为128
      int[] hash=new int[128];
      //右指针
      int right=0;
      //左指针
      int left=0;
      //while条件right<s.length()
      while(right<s.length()){
            int c=s.charAt(right++);
            //hash数组对应的位置+1
            hash[c]++;
            //说明left~right+1中有重复字符
            while(hash[c]>1){
                hash[s.charAt(left++)]--;
            }
          max=Math.max(max,right-left);
      }
      return max;
    }

  •  对入参进行判断,排除一些不合法的条件
  • 设置同向指针,left、right(相当于是两个前后指针)
  • right不断的向后走,记录中途的字符,用hash表进行统计,如果统计时发现hash[i]>1,就说明当前字符在之前已经出现过
  • left向后走,找到重复的元素位置上,然后移动到重复字符第一次出现的索引index +1的位置上,这时候计算max的值(最大长度)

解法二:

     public int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        int left=0;
        int max=0;
        //将字符串转换为char
        char[] str=s.toCharArray();
        int[] hash=new int[128];
        for(int right=0;right<s.length();right++){
            char c=str[right];
            hash[c]++;
            while(hash[c]>1){
                hash[str[left++]]--;
            }
            int val=right-left+1;
            max=Math.max(val,max);
        }
        return max;
    } 

大体过程如上题所示

解法三:

 public int lengthOfLongestSubstring(String s) {
             //创建一个map数组,值对应键值,然后两个索引,加一个最大值的子串长度
        //入参进行判断
        if(s.length()==0){
            return 0;
        }
        //创建一个map数组用于存放输出的单个字符-索引
        Map<Character, Integer> arr=new HashMap<>();
        //定义两个指针
        int i=0;
        int j=0;
        //定义最大的长度变量
        int max=0;
        //对字符串进行循环遍历
        for ( i = 0; i <s.length() ; i++) {
            //将对应索引的字符赋给变量key
            char key=s.charAt(i);
            //输出一个字符之后要和map中的数组进行比较,如果没有包含,直接加入到map数组中去,
            //如果有,则将j指针移到对应的i位置上去,再进行遍历
            if(arr.containsKey(key)){
                j=Math.max(arr.get(key),j);
            }
                //保存最大长度
                max=Math.max(max,i-j+1);
                //不断地往数组中加字符
                arr.put(s.charAt(i),i+1);
            
        }
        return max;
    }

     

  •  对入参进行判断
  • 创建一个hash表,记录索引的位置
  • 定义同向指针
  • 遍历右指针,收缩左指针
  • 每次遍历一个字符将字符添加到hash表中,并添加对应的索引
  • 输出一个字符之后和map中的key进行比较,如果没有包含,直接加到hash表中去
  • 如果有,则收缩左指针,再次进行遍历
  • 保存最大长度(左闭右闭)
  • 每次添加元素索引的时候添加对应元素的idnex+1,符合左闭的条件

      这时候肯定有人想问我,为什么在计算这类长度的时候,有的时候是s=right-left,而有的时候是s=right-left+1呢?这得看你自己定义的是左闭右开还是左闭右闭,有些人每次的糊里糊涂的做题,过了就没有再仔细深究,其实这与你的循环有着莫大的关系,仔细的同学已经发现我第一种解法用的是right-left,可是第二种解法就是用的right-left+1,接下来给大家揭秘这种应该怎么去选择

第一种方法:

 while(right<s.length()){
    int c=s.charAt(right++);
     ...
}

假如我们right已经到达了s.length-1的位置上,是不是进来还得做一次right++的操作

       由上图我们可以清楚的看到right取到了比我们s长度还要大的位置上,这种情况就是右开,所以长度就是right-left  

第二种方法:

for(int right=0;right<s.length();right++){
            char c=str[right];
          
        }

       假如我们right已经到达了s.length-1的位置上,进来也没有对right进行任何操作,所以最后right索引是停在b这个位置上

       由上图我们可以清楚的看到right取到了比我们s长度还要大的位置上,这种情况就是右闭,所以长度就是right-left+1  

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃橘子的Crow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值