Given a string, find the length of the longest substring without repeating characters.
Examples:
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. Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
就是说在一串字符串中找到最长的、这里边所有的字符都不重复的子串。
注意这里是子串,也就是连续的一串,由此可以考虑到,用两个指针标记这个子串的开始(i)和结束(j)。
如果j所指的字符在前边都没有出现过,当然就可以把j向后移;但如果出现过了,那么就要移动i(划重点!)。假如这个字符在k位置上出现过了,那么i就要移动到k+1.
开始时的时候想的是动态规划思路,但犯了一个很严重的错误,就是没有考虑到两个指针,考虑的是dp数组保存的是到当前位置的最长子串长度。如果发现这一个位置的字符在前边出现过了,那么就把这一位置的dp置为(当前位-前一次出现位置)的差值。但是如果从某一位开始,子串重置了(就是前边有重复的,把前边截掉了),那么出现与否的vis数组应该从哪里开始改变呢? 势必又要再多一重循环。。。
所以,根据这个题的特性来,首指针和末指针很有必要。虽然是两个循环嵌套,但是内层循环只走了一次,所以时间O(2*n).也就是O(n)。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
bool vis[666] = {false};
int i = 0, j = 0, ans = 0;
while(j < s.length())
{
if(vis[s[j]] == false)
{
vis[s[j]] = true;
j++;
if(ans < (j - i))
ans = j - i;
}
else
{
while(s[i] != s[j])//不用vis标记前一次出现是在哪里,直接从i开始往后找,边找边改,找到和j位字符相同的就停止
{
vis[s[i]] = false;
i++;
}
i++;
j++;
}
}
return ans;
}
};