题目大意:很好理解,求最长的没有重复元素的子串的长度,例如:“abcabcbb”结果是abc,长度3,“bbbbb”结果时b,长度1.
思路:用hash_map做的,因为每次找下一个字符时,都需要从前面的子串中进行查找操作,利用hash_map达到快速查找。因为不需要要排序操作,因此程序中是用的unordered_map。
1.令最长的无重复子串长度为max,i从0循环到字符串长度减去max
2.对每一个循环,从i开始,指定一个数len来指示从i开始能达到的长度,若从unordered_map hash中没有发现字符s[i],则将s[i]加入hash中,并将len++指向下一个字符,再进行判断是否在unordered_map hash中,依次循环执行。直到从unordered_map hash中找到此字符,即重复了。此时len即为从i开始的最大长度。
3.判断2找到的len与max的大小,若len大于max,则更新max。
4.按照最简单的思路,用1-3,一直循环,肯定能求出最大的max。但是,效率是个问题,提交时肯定会出现超时,有一个测试数据,string长度大于31000。在每一次i的循环中,在找到重复元素时,我进行了如下优化:
a.找到hash中那个重复元素的下标,若此下标大于i值,则将此下标值+1赋给i。例:"abcdecmnp",此时c重复,则hash中c的下标为2,大于第一个a的下标0,将i=2+1,因为从0-2的元素开始的子串长度必定小于从a开始的长度。
b.找到hash中那个重复元素的下标,若此下标等于i值,则继续判断下一个元素是否重复。例:“abcdabmn”,i=0,到a重复时,找到的重复下标为0,判断下一个元素b,直到没有发现重复或者进入a中。
优化的策略有点混乱,自己举例测试出来进行尝试的结果,感觉不是很好,还可以优化。提交运行ac了,运行时间为76ms,发现提交的c++代码一般都在16-30ms之间= =。代码如下:
#include
#include
#include
using namespace std;
class Solution{
public:
int lengthOfLongestSubstring(string s){
int max=0,len=0;
int off=0;
for(int i=0;i hash;
unordered_map::iterator hashit;
len=0;
while(hash.find(s[i+len])==hash.end()&&(i+len)max)
max=len;
off=0;
if(hash.find(s[i+len+off])!=hash.end())
{
while(hash.find(s[i+len+off])!=hash.end())
{
hashit=hash.find(s[i+len+off]);
if(hashit->second>off)
{
off=hashit->second+1;
break;
}
else
++off;
}
--off;
}
i=i+off;
}
return max;
}
};
int main()
{
string ss="aab";
Solution so;
int rr=so.lengthOfLongestSubstring(ss);
cout<
本来想改进一下代码的,结果毫无头绪。看了讨论区的算法思想,写了以下代码:
class Solution{
public:
int lengthOfLongestSubstring(string s) {
unordered_map hash;
unordered_map::iterator hashit;
int longest=0,m=0;
for (int i=0;isecond+1);
}
hash[s[i]]=i;
longest=max(longest,i-m+1);
}
return longest;
}
};
主要思路也是利用hash_map的快速查找,在hash中找到重复元素后,根据重复元素的下标和原子串的第一个位置下标相比,来更新m的值,已达到更新最长长度longest值的目的。此算法只需要O(n)的时间。并且,只用了一个hash_map就可以完成操作,因为如果“abcacdeb“,比如b值,前面已经存到hash_map中了,但是,此时m值指示的是子串的起始位置为3,因此即使可以找到,但是不会影响长度的计算。
反观自己写的,对每一个i需要进行一个循环,还需要分配hash_map,直到找到重复时才停止循环,虽然有优化可以使i值进行跳跃,不处理长度肯定小于max的情况,但总的说来,复杂了许多。从提交的运行时间,上述代码只需56ms,自己的需要76ms。
2016.09.02更新 JAVA代码
public class Solution {
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int res = 1;
Queue q = new LinkedList<>();
q.offer(s.charAt(0));
Map map = new HashMap<>();
map.put(s.charAt(0), 0);
for (int i = 1; i < s.length(); i++) {
if (map.containsKey(s.charAt(i))) {
res = Math.max(res, i - map.get(s.charAt(i)));
while (!q.isEmpty() && q.peek() != s.charAt(i)) {
map.remove(q.poll());
}
q.poll();
map.put(s.charAt(i), i);
q.offer(s.charAt(i));
} else {
map.put(s.charAt(i), i);
q.offer(s.charAt(i));
res = Math.max(res, map.size());
}
}
return res;
}
}
优化,只用一个map:
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int res = 1;
Map map = new HashMap<>();
int low = -1;
for(int i = 0; i < s.length(); i++) {
if(map.containsKey(s.charAt(i))) {
low = Math.max(low, map.get(s.charAt(i)));
map.put(s.charAt(i), i);
} else {
map.put(s.charAt(i), i);
}
res = Math.max(res, i - low);
}
return res;
}