【LeetCode #3 题解】 无重复字符的最长子串

一、题目

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

  • 示例 1:
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
  • 示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1
  • 示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

二、题解一:双指针暴力查找法 8ms 5.4M

// 暴力查找法
int lengthOfLongestSubstring(char * s){
    char *begin=NULL, *end=NULL, *p=NULL;
    int result=0;

    begin = s;     // 字串开始指针
    end = s;     // 字串结束指针

    // 是否走到了字串最末尾
    while( (*end) != '\0' ){ 

        // 此时将当前end 字符与前面的所有字符依次匹配
        p = begin;

        // 当动态匹配指针走到 end 字符处时,结束前面字串匹配
        while( p != end ){   

            // 处理当前字符与前面任意字符存在重复的情况
            if( *end == *p ){

                // 保存长度
                if( (end-begin) > result){
                    result = end - begin;
                }
                // 将start 置于 p + 1处,重新进行下一轮匹配
                begin = p+1;
                break;
            }
            p++;
        }
        end++;      // 开始匹配下一个字符
    }

    // 处理特殊情况,也就是走到末尾时,未看到重复的字符
    result = result > end - begin ? result : end - begin;

    return result;
}

运行结果如下:
在这里插入图片描述


三、惊呆:双指针暴力查找法 优化后 4 ms ? 假的

在前面的基础上,将 if 判断语名修改为三元表达式,时间从 8ms 变为 4ms ,有点不敢相信。。。
代码如下:

// 双指针暴力查找法

int lengthOfLongestSubstring(char * s){
    char *begin=s, *end=s, *p=NULL;	
    int result=0;

    // 是否走到了字串最末尾
    while( (*end) != '\0' ){ 

        // 此时将当前end 字符与前面的所有字符依次匹配
        p = begin;

        // 当动态匹配指针走到 end 字符处时,结束前面字串匹配
        while( p != end ){   

            // 处理当前字符与前面任意字符存在重复的情况
            if( *end == *p ){

                // 保存长度
                result = (end-begin) > result ? end - begin : result;
                
                // 将start 置于 p + 1处,重新进行下一轮匹配
                begin = p+1;
                break;
            }
            p++;
        }
        end++;      // 开始匹配下一个字符
    }

    // 处理特殊情况,也就是走到末尾时,未看到重复的字符
    result = result > end - begin ? result : end - begin;

    return result;
}

这个结果确实不敢相信,我怀疑是服务器运行的差异,经过多次运行,发现确实是这样,和三元表达式没半毛钱关系:
在这里插入图片描述


3.1 优化点1:指针赋值初始化,优化0.2M 内存

虽然前面的结果有问题,但赋值初始化,经过多次实测,确实优化了内存,虽然效果不明显。
但养成这个习惯还是好的

将代码指针初始化赋值,实测结果优化 0.2M 内存。
修改为:

    char *begin=NULL, *end=NULL, *p=NULL;
    begin = s;     // 字串开始指针
    end = s;     // 字串结束指针

=====>

	char *begin=s, *end=s, *p=NULL;	

实测结果:
在这里插入图片描述


四、题解二:利用数组内容判定是否重复

在第一种方法中,我们使用两个指针,
一个指针用来从字串头走到尾,第二个指针用来再次遍历字串判定是否重复。
因为,本方法就是对第二个指针来进行优化,
通过数组查表法来判定是否重复,避免指针再次遍历。

// 解法二、利用数组判定是否重复
// 

#define HASH_LEN 128

int lengthOfLongestSubstring(char * s){
    char *p = s;
    int max_count=0, start=0; 

    // 定义hash 数组, ascii 最大只有128个字符
    int hash_s[HASH_LEN];   

    // 重置所有数组值为 0
    memset(hash_s, 0x0, sizeof(hash_s));

    while(*p != '\0'){  
        
        // 通过数组中的值来判定是否重复
        // 如果字母是首次出现,hash_s[x]应该为0
        // 如果读取数组内容 > 0, 说明重复了,且其索引为 hash_s[x] -1
        // 如果读取数组内容 < start ,则说明字母在之前,不用管
        if( hash_s[ *p ] != 0 && hash_s[ *p ] >= start ){

            // 更新字串大小
            max_count = max_count > p-s - start  ? max_count : p-s - start ;

            // 更新字串起始位置为 i+1
            start = hash_s[*p]; 
        }

        // 此入之所以加 1 是避免 -1 的操作
        hash_s[*p] = p-s + 1; 

        p++; 
    }

    // 更新字串大小
    max_count = max_count > p-s - start  ? max_count : p-s - start ;

    return max_count;
}

运行结果如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章