寻找字串的问题常常用到滑动窗口法,就是利用两个下标之间的间距去解决问题
先说我的想法,前面的坐标去取元素,然后去和前面的元素数组去比较(看这个数组里是否包含这个元素,如果包含返回此坐标,如果不包含,开始下次循环)。如果前面数组元素包含upIndex元素,就让underIndex等于返回下标+1,目的就是让underIndex和upIndex里面不包含重复的元素。这样也有一个问题,就是最后一个元素无法判断…下面为本人代码(有BUG)
public int lengthOfLongestSubstring(String s) {
char[] ss = new char[s.length()];
int length = 1;
int underIndex = 0;
int upIndex = 1;
for (int i = 0; i < s.length(); i++) {
ss[i] = s.charAt(i);
int index = belongsTo(s.charAt(upIndex), ss, underIndex, upIndex);
if (upIndex - underIndex > length){
length = upIndex - underIndex;
}
if (index != -1) {
underIndex = index+1;
}
if (upIndex < s.length()-1){
upIndex++;
}
}
return length;
}
public int belongsTo(char s,char[] ss,int m,int n){
for (int i = m; i <= n; i++) {
if (s == (ss[i])){
return i;
}
}
return -1;
}
经过一晚上的折磨还是看了评论区,看到一个和我的思想类似,但是他的方法更好,他是利用HashMap的key值唯一性来判断是否重复(就是利用这点来取代我第二个方法)这样可不用考虑最后一个元素的问题,不得不佩服。下面是源码
public static int lengthOfLongestSubstring(String s) {
int length=0,left=0,right=0;
Integer n ;
HashMap<Character, Integer> hm = new HashMap<>();
for (right=0; right < s.length(); right++) {//右窗逐个滑动
n = hm.put(s.charAt(right), right);//每个新字符放入hashMap。如果有重复,即第right号字符与前面的第n号字符重复,则hashMap中right会替代n,并返回n。
if (n != null) {//如果发现重复字符,第n号字符
if(n>=left){//重复的字符如果落在窗内,则左窗直接收缩至该元素的后一个元素,无需逐个收缩
length = Math.max(length,(right-left));//左窗收缩前,先记录最大长度,即从第left号到第right-1号字符,共(right-1)-left+1=right-left个元素
left=n+1;//左窗直接收缩至该字符后面一个元字符
}
}
}
//如果遍历到最后一个字符之后,都没有重复,则再刷新一次Length,此时right = s.length()
length = Math.max(length, (right-left));
return length;
}
最后来说终极大佬的办法,代码非常简洁,非常难懂,但是理解了上面的思想会对理解此方法有一定的帮助。他是利用ASCII码来决定元素在数组的存放位置及出现的次数。他里面有两个max函数,第一个的作用就是为了判断这个元素是否已经出现过。如果后面大就是重复元素,如果前面大就是非重复元素。第二个max函数是记录连个坐标之间的距离的。其实他的i相当于我的upIndex,start相当于我的underIndex,这个大佬的办法属实太经典了,绝非凡人,耐人寻味
public int lengthOfLongestSubstring(String s) {
// 记录字符上一次出现的位置
int[] last = new int[128];
for(int i = 0; i < 128; i++) {
last[i] = -1;
}
int n = s.length();
int res = 0;
int start = 0; // 窗口开始位置
for(int i = 0; i < n; i++) {
int index = s.charAt(i);
start = Math.max(start, last[index] + 1);
res = Math.max(res, i - start + 1);
last[index] = i;
}
return res;
}