给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
第一时间想到的是列出给定字符串的所有子串,然后找出所有子串中无重复字符中的最长的,根据这一思路写出如下代码:
public class Solution3 {
public int lengthOfLongestSubstring(String s) {
int len=0;
String childStr="";
//将所有的可能的连续子串列出
ArrayList ls = new ArrayList();
for(int i=0;i<s.length();i++){
for (int j=i+1;j<s.length();j++){
String tem = s.substring(i,j);
ls.add(tem);
}
}
for (int i=0;i<ls.size();i++){
String cs = ls.get(i).toString();
// System.out.println(cs);
if (!isHasSameStr(cs)&&len<cs.length()){
len=cs.length();
childStr=cs;
}
}
System.out.println("最长子串:"+childStr);
System.out.println("最长子串长度:"+len);
return len;
}
//使用set集合判断是否有重复字符
public boolean isHasSameStr(String s){
Set set = new HashSet();
String[] ls = s.split("");
for (int i=0;i<ls.length;i++){
set.add(ls[i]);
}
if (set.size()<s.length()){
return true;
}
return false;
}
}
执行通过,但是很遗憾,当s=" "时,结果为0,错误了,然后查代码,发现是substring边界的问题,其第二个参数为截取结束的位置但不包括,更改上述代码:
public class Solution3 {
public int lengthOfLongestSubstring(String s) {
int len=0;
String childStr="";
//将所有的可能的连续子串列出
ArrayList ls = new ArrayList();
for(int i=0;i<s.length();i++){
for (int j=i+1;j<=s.length();j++){
String tem = s.substring(i,j);
ls.add(tem);
}
}
for (int i=0;i<ls.size();i++){
String cs = ls.get(i).toString();
// System.out.println(cs);
if (!isHasSameStr(cs)&&len<cs.length()){
len=cs.length();
childStr=cs;
}
}
System.out.println("最长子串:"+childStr);
System.out.println("最长子串长度:"+len);
return len;
}
//使用set集合判断是否有重复字符
public boolean isHasSameStr(String s){
Set set = new HashSet();
String[] ls = s.split("");
for (int i=0;i<ls.length;i++){
set.add(ls[i]);
}
if (set.size()<s.length()){
return true;
}
return false;
}
}
提交,悲剧的是超时了,让后想着减少执行时间,想的是在列出子串的地方做文章,在二层循环的时候,只要子串中出现重复的字符,那么之后的子串就没必要列出来了,再次修改代码:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class Solution3 {
public int lengthOfLongestSubstring(String s) {
int len=0;
String childStr="";
int step=1;
//将所有的可能的连续子串列出
ArrayList ls = new ArrayList();
for(int i=0;i<s.length();i++){
for (int j=i+step;j<=s.length();j++){
String tem = s.substring(i,j);
if (isHasSameStr(tem)){
if (step<tem.length()-1){
step=tem.length()-1;
}
break;
}else{
if (len<tem.length()){
len=tem.length();
childStr=tem;
}
}
}
}
System.out.println("最长子串:"+childStr);
System.out.println("最长子串长度:"+len);
return len;
}
//使用set集合判断是否有重复字符
public boolean isHasSameStr(String s){
Set set = new HashSet();
String[] ls = s.split("");
for (int i=0;i<ls.length;i++){
set.add(ls[i]);
}
if (set.size()<s.length()){
return true;
}
return false;
}
public static void main(String[] args) {
Solution3 s3 = new Solution3();
String s="avvhrxyhbeplapvwncwydwgypimhmnwmksvcpulsyadapbwfdsdjqmhfutmgilutdqxumimmlrmauifyalhqxq";
s3.lengthOfLongestSubstring(s);
}
}
提交勉强通过。
官方题解
暴力解法都比我的要简练,还需要努力啊。第三种方法看的有点晕。
补充滑动窗口的解法,主要原理是从第一个字符开始往hash表中放,已存在则将其从hash表中删除,外层循环+1,开始从下一个字符开始计算长度,循环往复
class Solution {
public int lengthOfLongestSubstring(String s) {
//滑动窗口
int len = s.length();
Set<Character> set = new HashSet<>();//保存无重复的字符
int right = -1;
int ans=0;
for(int i=0;i<len;i++){
if(i!=0){
set.remove(s.charAt(i-1));
}
while(right+1<len&&!set.contains(s.charAt(right+1))){
set.add(s.charAt(right+1));
right++;
}
ans=Math.max(ans,right-i+1);
}
return ans;
}
}