LeetCode 3、无重复字符的最长子串(C)


  作者只是一个小白,最近希望能提升自己的代码水平,所以开始刷leetcode。写博客是为了整理自己的学习内容,难免会出错。如果有大大发现,非常欢迎指正哦!


题目:3、无重复字符的最长子串

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

实例:

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


题解

  这道题还是比较明显要用滑动窗口来做。我们想象有一个框在s字符串上滑动,框的两边都只能向右移动。
  ①框的right边每次向右移一步,使框内增加一个新字符;
  ②当新进入的字符与框内的字符不重复时,则right边向右移,left边不动。并将新的len = right-left+1和之前存储的旧len中的较大值存入len中;
  ③当新进入的字符与框内的字符重复时,则left边向右移,一直到框内字符不重复。重复第①步。
  直到新字符为空,即整个字符串跑完,程序结束。
 
测试用例:s = “pwwelw”,left = right = 0,len = 0(为无重复字符最长长度), list = “”(为框内字符串)

  1. left = 0, right = 0, len = 1, list = “p”
  2. left = 0, right = 1, len = 2, list = “pw”
  3. left = 0, right = 2, len = 2, list = “pww”,检测到有重复字符,则left边向右移
  4. left = 1, right = 2, len = 2, list = “ww”
  5. left = 2, right = 2, len = 2, list = “w” ,没有重复字符,right边继续向右移
  6. left = 2, right = 3, len = 2, list = “we”
  7. left = 2, right = 4, len = 3, list = “wel”
  8. left = 2, right = 5, len = 3, list = “welw”
  9. left = 3, right = 5, len = 3, list = “elw”
    10.left = 3, right = 6, len = 3, list = "elw空 ",因为新字符为空,结束。

代码一

执行用时:4ms
排名:超过 77% 提交记录

int lengthOfLongestSubstring(char * s){
    int result = 0;
    char *left = s , *right = s , *p;

    while(*right != '\0'){

        for(p = left; p < right ; p++){
            if(*p == *right){
                left = p + 1;
                break;
            }
        }

        result = (right - left + 1) > result ? (right - left + 1) : result;

        right++;
    }

    return result;
}

  这段代码就是按上面的思路写的。其中检查是否有重复字符,是通过for循环来判断。只要将新字符和框内每个字符进行比对就行。

  那速度更快的代码是怎么样的呢?

代码二

执行用时:0ms
排名:超过 100% 提交记录

/*
使用 start 标识起始位置,end 结束字符,使用一个map标识是否遇到重复字符,遍历到有重复的字符,则start++。end - start + 1 就是不重复的字符串长度。
*/
int lengthOfLongestSubstring(char * s){
    int start = 0, end = 0, maxlen = 0;
    char map[128] = {0}; //收集字符,出现则ASCII对应位置为1
    map[(int)*(s+start)] = 1;
    
    while( *(s+end) != 0 )
    {
        maxlen = maxlen>(end-start+1)?maxlen:(end-start+1);
        ++end;
        while( 0 != map[ (int)*(s+end) ] )//*(s+end)处的字符已经出现一次
        {
            map[ (int)*(s+start) ] = 0;
               ++start;
        }
        map[(int)*(s+end)] = 1;
    }
    
    return maxlen;
}

  这段代码整体思路和上面的是一样的。区别就在于它判断重复字符的方式。它维护了一个map表,其中1代表对应的字符处于滑动窗口中,0代表不在窗口里。其中

    map[(int)*(s+start)] = 1;

这一句我当时一下子没读懂。我们举个例子。
  经过上一步map初始化后,map应该如下图所示,均为0。

map0000
index……112113……

我们假设:
s = “pwew”,start = 0
那么*(s+start)就代表是s字符串的第一个字符“p”,而(int)*(s+start)就是取字符“p”的ASCII码,即112,所以将map[112]=1。如下表

map0100
index……112113……

  这一步理解了就比较简单了。1代表对应的字符处于滑动窗口中,0代表不在窗口里。我们之前是将新字符和前面窗口中所有其它字符进行比较,判断是否重复,而它就直接根据ASCII码查map表,看看是1还是0,就可以知道有没有重复了。
  我感觉这其实也是一种哈希表,代替了for循环。以后要有意识多用用哈希表。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值