题目链接:
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
变更:无重复子串的最长子串的内容(求子串,原题求子串长度)
思路:双指针滑动窗口法
思路分析示例:
以frankissohandsome为例,我们要从中找出我们想要的子串,那少不了需要遍历,我们设置两个变量from,to
,分别存储寻找的目标子串在原字符串中的首尾位置。
首先,from
和to
的初始值都为0
(String的序号从0开始),子串长度length
= 1,最大子串长度maxLength
= 1。
然后,我们将to
的指向往后移动,并判断新遍历的字符是否已经存在于子串中,如果不存在,则将其加入子串中,并将length
进行自增。
直到找到一个已存在于子串中的字符,或者to
到达字符串的末尾。这里,我们找到了一个重复的s
,序号为7
,此时的子串为frankis
,将此时的子串长度与最大子串长度相比较(目前为0),如果比最大子串长度大,则将最大子串长度设置为当前子串长度7
。
接下来,我们继续寻找符合条件的子串,这里比较关键的一点是下一个子串的起始位置,这里我们将from
直接跳到了序号为7
的位置,因为包含ss
的子串显然都不能满足要求。
依照之前的方法,找到第二个候选的子串sohand
,长度为6
,比目前的最大子串长度小,所以不是目标子串。
接着继续寻找,找到另一个候选子串ohands
,长度小于最大子串长度,不是我们的目标子串
继续寻找
to
到达了字符串末尾,找到另一个候选子串handsome
,长度大于最大子串长度,这就是我们的目标子串。
Java代码:
public static int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int result = 0;
for (int start = 0, end = 0; end < s.length(); end++) {
char strChar = s.charAt(end);
if (map.containsKey(strChar)) {
start = Math.max(start, map.get(strChar));
}
result = Math.max(result, end - start + 1);
map.put(strChar, end + 1);
}
return result;
}
public static String longestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int result = 0;
int begin = 0;
for (int start = 0, end = 0; end < s.length(); end++) {
char strChar = s.charAt(end);
if (map.containsKey(strChar)) {
start = Math.max(start, map.get(strChar));
}
if (end - start + 1 >= result) {
begin = start;
result = end - start + 1;
}
// result = Math.max(result, end - start + 1);
// System.out.println("start:"+start+" end:"+end+" result"+result);
map.put(strChar, end + 1);
}
return s.substring(begin, begin + result);
}