这个实现的方法千万种,我列举其中一个。此代码仅仅考虑ASCII中的字符 。
两种算法仅有略微差距,代码中详细说
算法一
public static int lengthOfLongestSubstring(String s) {
//定义一个 ASCII码范围的数组,每个ASCII都对应一个数字,所以字符串中每一个字符都可以变换成ASCII码
int arr[]=new int[128];
//将数组中的所有数置位-1;
for(int i=0;i<arr.length;i++) {
arr[i]=-1;
}
//定义一个游标start指向字符串第一个
int start=0;
//初始化无重复最长子串为res
int res=0;
//遍历字符串s
for(int j=0;j<s.length();j++) {
//获取每一个字符在ASCII码中对应的数字
int index=s.charAt(j);
//如果字符曾经在ASCII码中出现,则arr[index]就不为-1了,则start会变成arr[index]+1,即start游标指向重复字符的下一个,如果没出现则,arr[index]=-1,arr[index]+1=0,游标start不动。
start=Math.max(start, arr[index]+1);
//计算长度,j游标指向当前遍历的字符,start指向重复的字符的下一个字符,中间的所有字符都没有重复,所以j-start+1为无重复字符长度,因为要求的最长子串,所以要比较res和j-start+1哪个更大,取哪个。
res=Math.max(res, j-start+1);
//每一次执行完,都要把ASCII码对应当前字符的位置变成j,代表字符最后一次出现的位置。
arr[index]=j;
}
return res;
}
算法二
//与算法一比较,这个算法并没有给ASCII码数组赋值,默认值都为0。
public static int lengthOfLongestSubstring1(String s) {
int arr[]=new int[128];
int start=0;
int res=0;
for(int j=0;j<s.length();j++) {
int index=s.charAt(j);
//直接和arr[index]比较,不过不同的是,此时的arr[index]记录的并不是当前字符出现的最后一个位置,而是记录的是当前字符出现的下一个位置。
start=Math.max(start, arr[index]);
res=Math.max(res, j-start+1);
//记录当前字符出现的下一个位置
arr[index]=j+1;
}
return res;
}
用图解释算法一
算法一明白了算法二也能轻松明白。图中解释了一部分代码机制,后面的就是重复循环,就不一一画出。