[leetcode]_Longest Substring Without Repeating Characters
问题:求一个字符串中最长不重复子串的长度。
直接思路:以每个字符为出发计算最长不重复子串。TLE。O(n2),HashMap存储字符出现的位置。
代码:
1 public int lengthOfLongestSubstring(String s) { 2 Map<Character , Integer> temp = new HashMap<Character , Integer>(); 3 int len = s.length(); 4 int tempLen = 0,maxLen = 0; 5 int i = 0; 6 while(i < len){ 7 char ch = s.charAt(i); 8 temp.put(ch , i); 9 tempLen = 1; 10 for(int j = i + 1 ; j < len ; j++){ 11 char ch2 = s.charAt(j); 12 if(!temp.containsKey(ch2)) { 13 temp.put(ch2 , j); 14 tempLen++; 15 }else{ 16 if(tempLen > maxLen) maxLen = tempLen; 17 //这里我还很得意,下次从重复的字符的下一位开始,但是依旧是TLE 18 i = temp.get(ch2) + 1; 19 temp.clear(); 20 break; 21 } 22 } 23 } 24 return maxLen; 25 }
提交了很多次依旧TLE。不得其解,求助之。
网络上解题思路与我是一样的,当遇到重复字符时,下次再计算最长子串时从重复字符的下一个字符开始,但是为什么会TLE呢?经分析别人的代码后,发现。
这个思路没问题,TLE的原因在于原先判断重复地方后,在里层for循环重复计算了映射到map中的值(map中存储字符出现的位置,其实计算多少次值都是一样的),为了不重复计算此部分的map值,引入一个新的标记位start ,当重复位置在start之前时,对找最长子串不影响,直接更新map中的映射即可;当重复位置在start之后时,此时比较cur - start(此次的最长子串)是否能更新maxLen。这样将O(n2)优化为O(n)。
public int lengthOfLongestSubstring(String s) { Map<Character , Integer> hash = new HashMap<Character , Integer>(); int len = s.length(); int maxLen = 0,start = 0; for(int i = 0 ; i < len ; i++){ char ch = s.charAt(i); if(!hash.containsKey(ch)){ hash.put(ch , i); }else{ int last = hash.get(ch); if(last < start) hash.put(ch , i); //如果该字符上次出现的位置在start之前,对结果不产生影响,相当于这个位置已经被废掉的,直接更新即可。 else{ if(i - start > maxLen) maxLen = i - start; hash.put(ch , i); start = last + 1; //将start的位置更新为重复位置的下一位 } } } if(len - start > maxLen) maxLen = len - start; //循环结束时,需要对最后一个不重复子串的长度进行判断 return maxLen; }
另一个优化地方:
上面代码使用Map来存储字符出现位置,这里可用数组来模拟HashMap提高效率。申请一个int[] hashTable = new int[256];将其初始化为-1。256个包含了ASCII码表所有字符,之后遇见统计字符数量什么的,可参考这种方法。
提交后RunTime从528ms -> 424ms。