给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
有两个例子要注意一下:
输入 " " (中间是空格)
预期结果 1
输入 "au"
预期结果 2
法一 双指针
成功
执行用时 : 29 ms, 在Longest Substring Without Repeating Characters的Java提交中击败了74.25% 的用户
内存消耗 : 47.4 MB, 在Longest Substring Without Repeating Characters的Java提交中击败了63.67% 的用户
class Solution {
public int lengthOfLongestSubstring(String s) {
//一个指针pre指向无重复子字符串的开头,一个指针cur移动指向当前字符(子字符串的结尾是cur-1),子字符串长度即为两者的差
//判断子字符串中 是否含有cur当前指向的元素,若不含,则cur+1;
//若包含,找出子字符串中重复该元素的位置,将pre指向下一个元素。cur继续回到判断这一步,直到将整个字符串都遍历
if(s.length() == 0)
return 0;
if(s.length() == 1)
return 1;
int pre = 0;
int cur = 1;
int res = 0;
while(cur < s.length() ){
res = Math.max(res, cur-pre);
String tmp = s.substring(pre, cur);
//System.out.println("tmp= " + tmp);
char x = s.charAt(cur);
//System.out.println("x= " + x);
if(tmp.contains(x+"") ){
int i = s.indexOf(x, pre);
pre = i+1;
}
cur++;
}
res = Math.max(res, cur-pre);
return res;
}
}
法二: 动态规划
维护一个数组dp[],dp[i]表示到以第i个字符结尾的不包含重复数组的子字符串的最大长度。
(我们并不保存最大不重复子字符串,只是存储其长度方便后续比较)
状态转移:
1. 第i个字符从未出现过,则dp[i] = dp[i-1] + 1;
2. 第i个字符出现过, 这时我们找出第i个字符最近一次出现的位置index,记两个的距离为d= i-index:
1) d<=dp[i-1],即这个字符出现在以第i-1个字符结尾的不包含重复数组的子字符串中,则dp[i] = d;
2) d>dp[i-1], 即这个字符没有出现在以第i-1个字符结尾的不包含重复数组的子字符串中,则dp[i] = dp[i-1] + 1 。
成功
执行用时 : 36 ms, 在Longest Substring Without Repeating Characters的Java提交中击败了59.84% 的用户
内存消耗 : 46.3 MB, 在Longest Substring Without Repeating Characters的Java提交中击败了65.79% 的用户
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0)
return 0;
int[] dp = new int[s.length() ];
dp[0] = 1;
int res = 1;
for(int i=1; i<dp.length; i++){
char x = s.charAt(i);
if(s.contains(x+"") ){
int index = s.lastIndexOf(x, i-1);
int d = i-index;
if(d > dp[i-1])
dp[i] = dp[i-1] + 1;
else
dp[i] = d;
}
else
dp[i] = dp[i-1] + 1;
res = Math.max(res, dp[i]);
}
return res;
}
}