请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
动态规划
* abcabcbb
* dp[j]保存以j结尾的最长子串
* dp[0] = 1
* dp[1] = dp[0]+1 = 2
* dp[2] = dp[1]+1 = 3
* dp[3] = 3-0 = 3
* dp[4] = 3-0 = 4
* ...
*
* i表示上次出现array[j]元素的位置
*
* if j-i <= dp[j-1] dp[j] = j-i
* j-i > dp[j-1] dp[j] = dp[j]+1
*
* if i不存在 dp[j] = dp[j-1]+1
public static int lengthOfLongestSubstring(String s) {
if (s == null || s.length() <= 0) {
return 0;
}
//定义dp数组
int[] dp = new int[s.length()];
//定义map,保存上次出现的位置
HashMap<Character, Integer> map = new HashMap<>();
int max = 1;
dp[0] = 1;
map.put(s.charAt(0),0);
for (int i = 1; i < dp.length; i++) {
//拿到上次出现的位置
Integer lastLoc = map.get(s.charAt(i));
if (lastLoc == null) {
//上次没有出现过
map.put(s.charAt(i),i);
dp[i] = dp[i-1] + 1;
if (dp[i] > max) {
max = dp[i];
}
continue;
}
if ((i-lastLoc) <= dp[i-1]) {
dp[i] = i - lastLoc;
} else {
dp[i] = dp[i-1] + 1;
}
map.put(s.charAt(i),i);
if (dp[i] > max) {
max = dp[i];
}
}
return max;
}
这里其实dp数组是不需要的,可以使用一个临时变量来进行替代
滑动窗口
* 解题思路:滑动窗口,定义左右指针,右指针可以一直往前走,走一步判断是否有重复,
* 有重复左指针收紧窗口直到
* 没有重复元素,然后做一次位置的记录
public static int lengthOfLongestSubstring2(String s) {
if (s == null || s.length() <= 0) {
return 0;
}
HashSet<Character> set = new HashSet<>();
int left = 0 , right = 0,res = 0;
while (right < s.length()) {
char c = s.charAt(right++);
//加完判断是否能走,不能走则收紧窗口
while (set.contains(c)) {
set.remove(s.charAt(left++));
}
set.add(c);
//记录一次位置
res = Math.max(res,right-left);
}
return res;
}