【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;
}
运行结果如下: