无重复字符串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
题目评价:这道题和最长的回文字符串看似类似但有很大差别。
思路1:
最开始想到的是动态规划,str[i—n]的无重复判定和str[i—(n-1)]+str[n]相同,即str[n]是否在str[i—(n-1)]中。以此完成代码。
public int lengthOfLongestSubstring(String s) {
int length=s.length();
if(length==0) {
return 0;
}
int max=1;
boolean[][] rec=new boolean[length][length];
for(int i=length-1;i>=0;i--) {
rec[i][i]=true;
}
for(int i=0;i<=length-1;i++){
for(int n=i+1;n<=length-1;n++){
if(rec[i][n-1]) {
if(check(s,i,n)) {
rec[i][n]=true;
if(n-i+1>max)max=n-i+1;
}else {
rec[i][n]=false;
}
}else {
rec[i][n]=false;
}
}
}
return max;
}
static boolean check(String s,int a,int b) {
char temp=s.charAt(b);
for(int i=a;i<=b-1;i++) {
if(s.charAt(i)==temp)return false;
}
return true;
}
代码分析:这个算法相当笨拙,虽然是动态规划,但是并没有太多实际上的时间减少,是一个O(n^2)的时间和空间复杂度。
结果如下:
正确思路:
从str[i]到str[n]开始,记录这个范围中的字符串,如果没有重复就让n++,如果有重复就让i++。记录这个过程中的最大距离。
public int lengthOfLongestSubstring(String s) {
int length=s.length();
Set<Character> occ = new HashSet<Character>();
if(length==0||length==1) {
return length;
}
int max=0;
int n=1;
int lon=0;
int temp=0;
occ.add(s.charAt(0));
for(int i=0;i<=length-max-1;){
while(n<length&&!occ.contains(s.charAt(n))) {
occ.add(s.charAt(n));
n++;//没有重复就让n++
}
if(n-i>max)max=n-i;
while(i<n&&n<length&&occ.contains(s.charAt(n))) {
occ.remove(s.charAt(i));
i++;//有重复就让i++
}
}
return max;
}
代码评析:参考了leetcode标准答案的思路,循环的嵌套过多,导致最差情过于不是很理想。例如“abcdrfghigklmm”当最后一个字符和倒数第二个字符重复的时候,str[i]需要从0一直增长到m才能进行后面的。所以需要对字符串检索两遍。