一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
一、描述
给定一个字符串
s,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 10^4s由英文字母、数字、符号和空格组成
二、分析
子串一定连续!子序列不一定连续!
子串必须以i字符结尾时的最长,字符串的每个位置过一遍,就求出了答案 max = Math.max(max,xx)
因为不管哪个子串,一定以某个位置结尾,把所有位置求一遍,答案必在其中
那么怎么求每个位置的答案呢?
假设来到了i位置(字符a),它能往左推到的距离有多远?能往左推多远,取决于因素一和因素二哪个离我近
有两种可能性:
- 上次a出现的位置(因素一)
- i-1位置结尾往左推了多远(因素二)
上次a出现的位置比较近
i-1位置结尾往左推的距离比较近
优化:数组实现哈希表功能
三、实现
public static int lengthOfLongestSubstring(String s) {
if (s == null || s.equals("")) {
return 0;
}
char[] str = s.toCharArray();
// map (a, ?) (b, ?)
// a, 17
// map[97] = 17
int[] map = new int[256];
for (int i = 0; i < 256; i++) {
map[i] = -1;
}
// 收集答案
int len = 0;
int pre = -1; // i-1位置结尾的情况下,往左推,推不动的位置是谁
int cur = 0;
for (int i = 0; i != str.length; i++) {
// i位置结尾的情况下,往左推,推不动的位置是谁
// pre (i-1信息) -> pre(i 结尾信息)
pre = Math.max(pre, map[str[i]]);
cur = i - pre;
len = Math.max(len, cur);
map[str[i]] = i;
}
return len;
}