最长无重复子串
思路:滑动窗口
【难点1】滑动窗口的起始和结束位置
窗口的起始位置为第一个重复元素的下一个位置,结束位置为第二个重复元素的下一个位置。
例如:“abcdbm”,第一次遍历,滑动窗口的位置为i=0, j=0
,接下来,j
不断循环寻找重复元素,最终停止在j=4
的位置上;则下一次滑动窗口的位置为i=2, j=5
。
这样做的原理在于,包括第一个重复元素的字符串长度不能再增加,于是需要去掉第一个重复元素;而又已知在第一个和第二个重复元素之间,不存在重复元素,因此滑动窗口的结束位置在第二个重复元素之后。
【难点2】查找重复元素的集合如何设置
每次查找重复元素,所查找的集合应该是当前字符串第一个元素之后到当前位置的所有字符,也就是第一个重复元素之后的元素,而没有第一个重复元素之前的元素。
【难点3】边界条件
要注意如何处理字符串长度为1的情况。
public static int lengthOfLongestSubstring(String s) {
int ret = 0;
int n = s.length();
int nexti = 0, nextj = 0; //表示下一个i和j的位置
int i = nexti, j = nextj;
Map<Character, Integer> hashTable = new HashMap<Character, Integer>();
if (n > 0)
{
while (i < n)
{
hashTable.put(s.charAt(i), i);
boolean flag = false;
while (j < n)
{
//终止当前字符串出口1,内层循环结束
if (hashTable.containsKey(s.charAt(j)))
{
int pos = hashTable.get(s.charAt(j));
if (pos != j && pos >= i)
{
hashTable.put(s.charAt(j), j);
nexti = pos + 1;
nextj = j + 1;
ret = ret > j-i ? ret : j-i;
i = nexti;
j = nextj;
flag = true; //表示i已经被设置过了
break; //退出循环
}
}
hashTable.put(s.charAt(j), j);
j++; //正常遍历
}
//终止当前字符串出口2,没有在内部终止,直接循环到结束,外层循环结束
if (j == n)
{
return ret > j-i ? ret : j-i;
}
// j != n 之后,i的值可能给定,也可能没有给定,根据flag判断
if (!flag) //还没有给出新的i的值
{
i++;
}
}
}
return ret > j-i ? ret : j-i;
}