Description
Given a string, find the length of the longest substring without repeating characters.
Example:
Given"abcabcbb"
, the answer is"abc"
, which the length is 3. Given"bbbbb"
, the answer is"b"
, with the length of 1. Given"pwwkew"
, the answer is"wke"
, with the length of 3.
Solution
这种问题如果让人解决,很直观地会采取从左到右进行扫描并维护不重复子串。
当出现重复字符时,从前一重复字符的下一个字符开始重新开始扫描计数,并在整个过程中不断对当前不重复子串的最大长度进行更新。
为了便于查询当前字符是否已经存在,可以采用map容器进行存储。但考虑到只有字符,直接使用一个长度为255的标记数组是一个更好的选择。
在标记数组中,以字符的ASCII值为下标,以字符串中相应的位置为值。
解决问题的算法即是通过编码,让计算机去模拟人的思维过程。
整个算法的执行过程如下:
① 对字符子串首位置、最大长度、当前长度进行初始化,并对整个标记数组赋值-1。
② 对字符串从左到右进行遍历。对于字符s[i],判断是否存在于标记数组。
③ 若字符不存在,在标记数组相应ASCII值下标处赋值当前字符在字符串中的位置,并将当前长度加1。
④ 若字符存在,将字符串中,“字符子串首位置”至“重复字符位置”前的字符在标记数组中重置为不存在,即赋值-1。当前字符子串长度相应的减去对应的个数,并将字符子串首位置更新为重复位置+1,将重复字符在标记数组中的值更新为最新出现的下标。
⑤ 判断当前长度是否大于最大长度,若大于,将当前长度赋值给最大长度。
⑥ 遍历结束后,返回最大长度。
算法实现代码如下:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//26个字母的标记数组
int mark[255];
for (int i = 0; i < 255; i++)
mark[i] = -1;
int maxLength = 0;
int length = 0;
int headIndex = 0;
for (int i = 0; i < s.length(); i++) {
int index = s[i] - '\0';
//尚未存在于当前字符串中
if (mark[index] == -1) {
mark[index] = i;
length++;
}
//已存在于当前字符串中
//即子串中出现重复
else {
int repeatIndex = mark[index];
//擦除重复字符前的键值对
for (int j = headIndex; j < repeatIndex; j++)
mark[s[j] - '\0'] = -1;
length = length - (repeatIndex - headIndex);
//对重复键值对的下标值进行更新
mark [index] = i;
//对字符串头进行更新
headIndex = repeatIndex + 1;
}
if (length > maxLength)
maxLength = length;
}
return maxLength;
}
};
在Leetcode上提交运行情况如下: