题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke"
,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
看到此题目,我们来分析一下:
比如题目中给的“abcabcbb”:
1.[a]
2.[a,b]
3.[a,b,c]
4.[a,b,c,a] ->[b,c,a]
5.[b,c,a,b] ->[c,a,b]
6.[c,a,b,c] ->[a,b,c]
7.[a,b,c,b] ->[b,c,b] ->[c,b]
8.[c,b,b] ->[b,b] ->[b]
代码如下:
package edu.ymm.about_str;
import java.util.LinkedList;
public class Str {
public static int lengthOfLongestSubstring(String s) {
int num=0;//记录最长子串长度
int current=0;//记录当前子串长度
char[] arr=s.toCharArray(); //将此字符串放在字符数组里面
LinkedList<Character> temp=new LinkedList<>();
for (int i=0;i<arr.length ;i++ ) {
//查看链表中此字符是否存在
if (!temp.contains(arr[i])) {
temp.add(arr[i]); //不存在就加进去
System.out.println("temp1" + temp);
current=temp.size(); //记录当前子串的长度
if (current>num)
num=current;
//如果新增字符与原子串中字符有重复的,删除原子串中重复字符及在它之前的字符,与新增字符组成新的子串
}else {
temp.add(arr[i]); //先将此重复的加进去
int first=temp.indexOf(arr[i]); //得到重复数当前的下标
for (int j=0;j<first ;j++ ) { //将重复数之前的字符删完
temp.remove();
System.out.println("temp3" + temp);
}
temp.remove();//第一个数与遍历到的重复直接删
System.out.println("temp2" + temp);
}
}
return num;
}
public static void main(String[] args) {
String str = "abcabcbb";
System.out.println(lengthOfLongestSubstring(str));
}
}
结果如下:(多加了输出方便理解)
上述的方法是根据分析的结果写下来的,没有考虑方便简洁的数据结构,下面我们来看另一种方法,也是时间复杂度最低的一种方法。
先看代码:
package edu.ymm.about_str; public class Str2 { public static int lengthOfLongestSubstring(String s) { int n = s.length(), ans = 0; int[] index = new int[128]; for (int j = 0, i = 0; j < n; j++) { i = Math.max(index[s.charAt(j)], i); ans = Math.max(ans, j - i + 1); index[s.charAt(j)] = j + 1; } return ans; } public static void main(String[] args) { String str = "abcabcbb"; lengthOfLongestSubstring(str); } }
还是看题目的例子:s="abcbadca"; i= 0;j=0
依次把{a:1,b:2,c:3}存入index,此时ans = 3,i=0,j=3;
下一次进入的时候,因为‘b'已存在index中,所以i会被设为2,即字符数组中第一个b的后一个位置。同时index里面的b对应的值会被更新为4,然后判断ans的值,同时index里面的b对应的值会被更新为4。