无重复字符的最长子串 Longest Substring Without Repeating Characters
题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
思路:
1.暴力解法:遍历所给字符串,逐个求出所有小于等于总字符串长度的子字符串,并计算每一个子字符串长度,再比较其内部是否有重复字符,求出无重复字符的最长子字符串。但该解法时间复杂度较高。参阅题解采用方法二。
2.滑动窗口法:在字符串中设置一个初始长度为0的滑动窗口 [ head , rear ),此时 head = rear ,将滑动窗口内部看作一个队列,将字符逐个存储到滑动窗口中,若窗口外下一个字符与窗口内字符不重复,则将窗口长度+1,并向右滑动 rear ,直至下一个字符与窗口内字符重复,则此时,我们找到的没有重复字符的最长子字符串是以 head 开头的不重复最长子串。对字符串中所有的head做此操作,即对字符串中每一个字符都采取rear右滑,记录以其开头的不重复最长子串,最后比较得到最长子串。
代码:
int lengthOfLongestSubstring(char * s){
int maxStrLen = 0; //不重复字符的最长子串长度,即题目所求
int winLen = 0; //滑动窗口长度、队列头尾
int winHead = 0;
int winRear = 0;
int winQueue[128] = {0}; //ASCII码有128个字符,滑动窗口内最多有128个不重复字符
int strLength = strlen(s); //字符串长度
if(strLength == 0){
return 0; //字符串为空返回0
}
while(winHead <= (strLength-1)){ //对每一个字符用滑动窗口遍历字符串
if(winQueue[s[winHead]]!=0){ //当滑动窗口不为空时开始查找窗口内重复字符
if(winQueue[s[winHead] ] > winRear){ //滑动窗口下一个字符蝠时,忽视外部子字符串
winRear = winQueue[s[winHead]]; //更新滑动窗口队尾,即rear右滑一个单位
}
}
winLen = winHead - winRear + 1; //更新计算滑动窗口长度
if(winLen > maxStrLen){ //若滑动窗口长度大于目前不重复子串长度
maxStrLen = winLen ; //则更新最大不重复子串长度为窗口长度
}
winQueue[s[winHead]] = winHead + 1;//存储字符串head字符的位置到队列中
winHead++; //,以head++字符开始滑动窗口遍历
}
return maxStrLen;
}