HashMap的应用可以提高查找的速度,键key,值value的使用拜托了传统数组的遍历查找方式,对于判断一个字符或者字符串是否已经存在的问题可以非常好的解决。而本题需要解决的问题就是判断新遍历到的字符是否已经存在于左left,右right,字符构成的子串之中。
解题思路:设置一个left作为子串的最左边的字符位置坐标,right不断向右遍历,并对每次遍历得到的字符进行判断,max作为最大的没有重复字符的子串长度。对于right遍历得到的新的字符,有两种情况:
一:在Hash表中没有,此时该字符为第一次出现,肯定不会与之前的字符重复,所以将其(<character,right>)put到Hash表中,将遍历得到的子串长度加一,并判断是否更新max.
二:在Hash表中存在,此时需要判断已经存在的该字母与left的位置关系,如果已经存在的charAt(right)字母在left左侧,说明right字母是在left--right子串中第一次出现,left继续保持不变,更新Hash表中的right字母的位置即可,(因为left 左侧的字母对之后的序列已经不会产生影响了,而left右侧新出现的right字母会影响之后序列的长度判断),增加left--right子串长度,并判断更新max;如果已经存在的right字母在left、或者left的右侧,说明left--right子串中出现了重复的字符,left直接跳到与right字母相同的字母的下一位mid即可(因为l从left到mid之前每一次遍历得到的子串left--right都会存在重复的字符并且长度还在减小),更新hash表中的charAt(right)字符位置信息
代码:
public class Solution { public int lengthOfLongestSubstring(String s) { if(s.length() == 0) return 0; int left = 0,right = 0,max = 0; HashMap<Character,Integer> map = new HashMap<Character,Integer>(); for(;right<s.length();right++){ if( map.containsKey(s.charAt(right)) ){ left = Math.max(left,map.get(s.charAt(right))+1 ); } map.put(s.charAt(right),right); //会将之前出现过的相同字母的坐标覆盖掉 max = Math.max(max,right-left+1); } return max; } }
没有想法时,可以先使用暴力,他会带你走近题目^_^。
下面记录一下自己第一遍写的代码,每次看到一道题目,第一个也是最常规的想法就是--暴力,通过两层循环(应该说是三层),先找出left--right子串,然后利用java内置函数判断一下,right字母是否存在于left--right子串中。(就当学习一下关于string的函数了)
public class Solution { public int lengthOfLongestSubstring(String s) { if(s.length() == 0) return 0; char []a = s.toCharArray(); int maxlen = 1; for(int i = 0;i<a.length-1;i++){ int midlen = 1; for(int j=i+1;j<a.length;j++){ String sub = s.substring(i,j); int index = sub.indexOf(a[j]); if(index == -1){ midlen++; } else{ i = i+index; break; } } if(midlen>maxlen) maxlen = midlen; } return maxlen; } }