剑指 Offer 48. 最长不含重复字符的子字符串
题目描述
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
输入输出
1 2 3 4 5 6 7 8 9 10 11 12
| 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
|
基本思路
- 双指针+哈希表:
- 哈希表统计s[j]最后一次出现的索引
- 更新左指针
- res记录res和j-i之间的较大值
- 动态规划 -> dp[j]代表以字符s[j]为结尾的”最长不重复子字符串”的长度
- i < 0 即s[j]左边无相同字符 则dp[j] = dp[j - 1] + 1
- dp[j - 1] < j - i 说明s[i]在子字符串dp[j - 1]区间之外 则dp[j] = dp[j - 1] + 1
- dp[j - 1] >= j - i 说明s[i]在子字符串dp[j - 1]区间之中 则dp[j]左边界有s[i]决定 即dp[j] = j - i
- 而因为i < 0时dp[j - 1] <= j恒成立 因而dp[j - 1] < j - i恒成立 因此2.1分支和2.2分支可合并 合并后:
- 最后求 max(dp[j - 1], dp[j]) 得到结果
$$
dp[j]=
\begin{cases}
dp[j-1]+1 & , dp[j-1]<j-i \\[3ex]
j-i & , dp[j-1] \geq j-i
\end{cases}
$$
java实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> dic = new HashMap<>(); int i = -1, res = 0; for(int j = 0; j < s.length(); j++) { if(dic.containsKey(s.charAt(j))) i = Math.max(i, dic.get(s.charAt(j))); dic.put(s.charAt(j), j); res = Math.max(res, j - i); } return res; } }
class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> dic = new HashMap<>(); int res = 0, tmp = 0; for(int j = 0; j < s.length(); j++){ int i = dic.getOrDefault(s.charAt(j), -1); dic.put(s.charAt(j), j); tmp = tmp < j-i ? tmp + 1 : j-i; res = Math.max(res, tmp); } return res; } }
|