剑指 Offer 48. 最长不含重复字符的子字符串
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
题解:
使用动态规划,动态规划解析:
状态定义
: 设动态规划列表 dp ,dp[j]代表以字符 s[j]为结尾的 “最长不重复子字符串”
的长度。
固定右边界 j,设字符 s[j]左边距离最近的相同字符为 s[i] ,即 s[i] = 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 -0恒成立,因而 dp[j - 1] < j - i恒成立,因此分支 1. 和 2. 可被合并。
所以状态转移方程为:
dp[j] = dp[j - 1] + 1 (dp[j - 1] < j - i)
dp[j] = j - i (dp[j−1]≥j−i )
最后返回dp数组最大值。
Java代码:
public static int lengthOfLongestSubstring(String s) {
if(s.length()==0)return 0;
int l = s.length();
int[] dp=new int[l];
int res = 1;
dp[0]=1;
for(int j = 1; j < l; j++) {
int i = j - 1;
while(i >= 0 && s.charAt(i) != s.charAt(j)) i--;
if(dp[j -1] < j - i)dp[j]=dp[j - 1] + 1;
else
dp[j] = j - i;
res = Math.max(res, dp[j]);
}
return res;
}