给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
下面为你提供LeetCode第三题"无重复字符的最长子串"的Java实现,包括滑动窗口和动态规划两种方法:
虽然动态规划通常不是解决「无重复字符的最长子串」问题的最优方法(滑动窗口更高效),但我们可以尝试用动态规划思路来分析和实现。
动态规划思路解析
-
定义状态:
设dp[i]表示以字符串第i个字符(下标为i)结尾的「无重复字符最长子串」的长度。 -
状态转移方程:
对于第i个字符s[i]:- 向前查找最近的与
s[i]相同的字符,设其下标为j。 - 如果找不到相同字符(
j = -1),则dp[i] = dp[i-1] + 1(直接延长前一个子串)。 - 如果找到相同字符(
j >= 0):- 若
j在dp[i-1]对应的子串范围之外(即i - j > dp[i-1]),说明s[i]与当前子串不冲突,dp[i] = dp[i-1] + 1。 - 若
j在dp[i-1]对应的子串范围内(即i - j <= dp[i-1]),则以s[i]结尾的最长子串只能从j+1开始,dp[i] = i - j。
- 若
public class LongestSubstringDP { public int lengthOfLongestSubstring(String s) { if (s == null || s.length() == 0) { return 0; } int n = s.length(); int[] dp = new int[n]; dp[0] = 1; int maxLen = 1; Map<Character, Integer> charLastPos = new HashMap<>(); charLastPos.put(s.charAt(0), 0); for (int i = 1; i < n; i++) { char currentChar = s.charAt(i); int lastPos = charLastPos.getOrDefault(currentChar, -1); // 状态转移 if (i - lastPos > dp[i - 1]) { dp[i] = dp[i - 1] + 1; } else { dp[i] = i - lastPos; } // 更新字符位置和最大长度 charLastPos.put(currentChar, i); maxLen = Math.max(maxLen, dp[i]); } return maxLen; } public static void main(String[] args) { LongestSubstringDP solution = new LongestSubstringDP(); System.out.println(solution.lengthOfLongestSubstring("abcabcbb")); // 输出3 System.out.println(solution.lengthOfLongestSubstring("bbbbb")); // 输出1 System.out.println(solution.lengthOfLongestSubstring("pwwkew")); // 输出3 System.out.println(solution.lengthOfLongestSubstring("")); // 输出0 } - 向前查找最近的与
}
651

被折叠的 条评论
为什么被折叠?



