题目描述:给定一个字符串s ,请你找出其中不含有重复字符的最长子串的长度。
示例:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
朴素解
一眼看完本题,我就又想到了优美的HashMap,因为map里面存的是键和值,这也就意味着键不可重复,如果添加相同的键进入map,则会将之前的值覆盖,而对于一个字符串,我们可以从左到右遍历此字符串,并且设置两个索引start和end,分别指向子串的开始和结束,那么对于字串的长度即等于end-start + 1(索引从0开始)。如下图:
对于d,我们循环到索引为2时就会遇到重复的情况,此时v为字串的结尾。而对于下一次字串的循环,则还需考虑d的下一个字符,此处为v,难以表述,建议看我下面程序自己试试:
public int lengthOfLongestSubstring(String s) {
// 此处首先计算s的长度和max_len同时定义有助于提高速度
int max_len = 0, n = s.length();
HashMap<Character, Integer> map = new HashMap<>();
//此处的j即为end,而i即为start
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
max_len = Math.max(max_len, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return max_len;
}
最终结果为5ms。
最优解
最优解类似上面的方法,只不过不用创建HashMap了,值得注意的是,index[s.charAt(j)]此代码将s.charAt(j)的字符返回为ascall码。
public int lengthOfLongestSubstring(String s) {
int n = s.length(), max_len = 0;
int[] index = new int[128];
for (int j = 0, i = 0; j < n; j++) {
i = Math.max(index[s.charAt(j)], i);
max_len = Math.max(max_len, j - i + 1);
index[s.charAt(j)] = j + 1;
}
return max_len;
}
此处之所以创建长度为128,是因为ASCLL码的最大字符长度为128。最终耗时果然最牛逼的。