听说今年南大机试有两道leetcode的原题,故开刷。今天下午刷了4道,leetcode有一个好处(或者说是坏处),就是不需要你去操心输入输出,直接完成提供给你的函数即可。代码编写、调试均可在网页上进行,这写起来还是挺爽的。多日不刷算法,手又有点生疏了,机试这种还是要多练啊。
进入正题,顾名思义这题就是求一个字符串的最长无重复字符子串。
我的思路是用一个数组记录每种字符出现的位置,当发生重复时,从上一次出现的位置的下一个字符开始继续搜索,这要能优化两层for循环原先的O(N^2)的算法。
代码如下:
class Solution {
public:
int vis[256];
int lengthOfLongestSubstring(string s) {
if(s.length()==0)
return 0;
int begin,len,max_len,end;
begin = end = len = max_len = 0;
while(end<s.length())
{
memset(vis,-1,sizeof(vis));
end = begin;
while(end<s.length()&& vis[s[end]] == -1)
{
vis[s[end]] = end;
end++;
}
max_len = max(max_len,end-begin);
begin = vis[s[end]] + 1;
}
return max_len;
}
};
但是可以看出,我在每次发生冲突后,更新一次begin后又将end重新赋值为begin,这样造成了不必要的重复搜索。
另一种思路是在发生重复时,向前一步步挪动begin,清除标记,知道不再有重复。可以严格证明该方法时间复杂度为O(n),其中移动end花费O(n),移动begin花费O(n),O(n)+O(n)=O(n)。
更好思路是,判断重复发生在begin之前还是之后,若在之后,则的确有重复,若在begin之前则说明不在该子串里,不会有冲突。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> dict(256, -1);
int maxLen = 0, begin = 0;
for (int i = 0; i != s.length(); i++) {
if (dict[s[i]] >= begin)
begin = dict[s[i]] + 1;
dict[s[i]] = i;
maxLen = max(maxLen, i - begin + 1);
}
return maxLen;
}
};