003题为无重复字符的最长字串,这一题不是很难,但我还是做了不少时间,因此还是写下来作为记录,同时为各位需要的朋友留下一点或许有用的信息吧。
接下来,就先读一下题目。
题目:
题目的描述已经很清楚了 ,我们在此就不再过多的再去解释了,直接进入正题吧。
在这一题中,我们要使用滑动窗口。
解题思路:滑动窗口
滑动窗口大概意思是两个指向两端的指针,使中间的字符串形成一个类似“窗口”的容器,窗口的大小可以随着指针的移动而发生变化。在现实生活中也有着实际类似的运用,如在计算机网络中,tcp协议在流量通信中会使用滑动窗口来实现流量控制。
首先确定窗口的最大值,即字符串的总长度,用len表示,用来作为结束标志,当右端的指针到达字符串尾部的时候,可认为判断结束。
在这一题中,我们可以利用滑动窗口的两端来计算当前无重复字串的长度。将左边指针设置为left,初始值为 0,右边指针设置为right,初始值为1。再将max值初始化为0.
int left = 0;
int right = 1;
int i = 0;
int len = 0;
int max = 0;
while(s[i] != NULL) {
i++;
}
len = i;
随后进入第一层循环——窗口右端是否到达串尾,若达到则结束循环。现在窗口已经建立,需要检查是否有重复字符,此处在套一个循环,设置检查标志flag,从left处开始检查,向右移动到right处停止。
若出现重复字符串则向left向右移动一位,若没有则right向右移动一位。
除此之外,在进行移位前需要进行计算当前长度,若flag = 0,窗口内的无重复字符串长为right + 1 - left,若flag = -1,则串长为right - left。
源代码如下:
int lengthOfLongestSubstring(char * s){
int left = 0;
int right = 0;
int i = 0;
int len = 0;
int max = 0;
int middle = 1;
while(s[i] != NULL) {
i++;
}
len = i;
while(right < len) {
int flag = 0;
for(int j = left; j < right; j++) {
if(s[right] != s[j]) {
continue;
}
else {
flag = -1;
break;
}
}
if(flag == 0) {
int son_string_len = right + 1 - left;
if(son_string_len > max) {
max = son_string_len;
}
right++;
}
if(flag == -1) {
int son_string_len = right - left;
if(son_string_len > max) {
max = son_string_len;
}
left++;
}
}
return max;
}
很明显,上面两种情况的区别无非是当前right所指的字符是否属于重复字符,即串长是否加一。
综上所述,我们只需要依次判断最右端的字符是否与前面的字符串有重复,并通过将情况分为有和没有来进行判断作不同处理。
不足与反思
我们在查询对比时,用的是在循环中进行,这样的查询效率较低,从而导致程序的执行速度变慢,对此我们可以通过数组来保存窗口内的字符。
利用对应字符的ASCII值,0表示无重复,1表示重复,当不发生重复时,将新加入的字符记录对应的数组位置,这样在查询的时候,我们就只需要O(1)的时间复杂度,就可以判断字符串是否重负。发生重复就可以将最左端的字符去除,并将left右移,直到字符串中无重复字符。
各位如果做过001.两数之和的话,其中的快速计算的方法和这个相当相似,理论上是可以提高计算的效率,但是本人并未尝试,有兴趣的话,可以进行尝试。
注:水平不足,还望包含,希望说错的地方还请各位在评论区指点一二,谢谢了!