题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串
先来看我自己的解法
package day01;
import java.util.Arrays;
public class 无重复字符的最长子串 {
public static void main(String[] args) {
int aa = lengthOfLongestSubstring("abcabcbb");
System.out.println(aa);
}
/*
* 思路如下:
* snum是存储了以每一个字符开头的不重复字符串的长度
* //如果字符串为空或者字符串的长度为1 就之间返回字符串的长度
* //先将字符串转换为字符数组 定义一个字符串curS,用来存放不重复的字符串,定义一个开关isStr,默认false,表示当前curS没有重复的字符串。
* //第一层循环 遍历字符数组 先将自身添加到curS里面,因为自身也算在长度里面
* //第二层循环 匹配不重复字符串.
* 可以解决abca的重复字符串 只能找出下次以自身开头的字符串截止(比如 以a开头去匹配不重复,那么只能找到以a结尾的不重复字符串)
* 如果是abcba 那么第二层循环只能找出abcb 中间的就不能匹配到
* //第三层循环 是为了解决中间的字符和后面字符的匹配问题
* 每次去遍历curS字符串,如果curS中的字符串和char[j]匹配到,就将isStr为true(代表找到了重复字符串),退出循环
*
* //回到第二层循环
* 如果isStr为true 将curs的长度存储到snum里面去,并将curS置空,方便下次循环,isStr=false,并退出第二次循环
* 如果isStr为false, 没有在curs找到重复的字符串
* 需要判断第二层循环的索引j 是否到达了字符串的末尾
* 如果没有到达末尾 就将char[j]添加到curS里面去
* 如果到达了末尾,就相当于以当前字符开头到字符串末尾,都没有找到重复的字符串
* 就需要将当前curS的长度+1 放入snum里面去,为什么要加一呢? 因为需要将最后一个字符也要算进去,并将curS置空
* 比如pwwkew 以k字串开头到末尾都没有找到重复的字符串,就需要在第二层循环索引j指向w
* 的时候将k开头的字符添加到snum里面去。
*
*
*
* */
public static int lengthOfLongestSubstring(String s) {
//如果字符串为空或者字符串的长度为1 就之间返回字符串的长度
if(s.length() == 0 || s.length() ==1){
return s.length();
}
int[] snum = new int[s.length()]; //用来存储以每个字符开头的无重复字符的长度
char[] chars = s.toCharArray();
//用来表明是否找到了重复的字符串
boolean isStr = false;
//记录当前字符串里面的不重复字串
String curS = "";
for (int i = 0; i < chars.length; i++) {
curS+=chars[i];
for (int j = i+1; j < chars.length; j++) {
for (int k = 0; k < curS.length(); k++) {
if(curS.charAt(k)==chars[j]) {
isStr = true;
break;
}
}
if(isStr){
snum[i] = curS.length();
curS = "";
isStr = false;
break;
}else{
if(j!=chars.length-1){
curS+=chars[j];
}else{
snum[i] = curS.length()+1;
curS = "";
}
}
}
}
int num = 0;
for (int i = 0; i < snum.length; i++) {
if(snum[i]>num){
num = snum[i];
}
}
return num;
}
}
是否感觉写的有点复杂…哈哈哈 可能是我有点傻,竟然把时间复杂度写道了O(n3).
看我在力扣上的运行
结果只超过了 百分之五的用户,哈哈哈哈.
再来看别人的解法
//移动窗口解法 始终保持在[start,end]里面没有重复的子串,并求出最大的长度
public static int lengthOfLongestSubstring1(String s){
int n = s.length(),ans=0; //ans表示字符串不重复字符的最大长度
Map<Character, Integer> map = new HashMap<>();
for (int start = 0,end=0; end < n; end++) {
char alpha = s.charAt(end);
if(map.containsKey(alpha)){
//如果发现了重复的字符串,就需要更新start位置,要保证[start,end]没有重复的字符串
//+1是表示移动到不重复的下一个字符
start = Math.max(map.get(alpha)+1,start);
}
ans = Math.max(ans,end-start+1);
//用来存储字符所在的位置.,遇到重复的字符,会覆盖前面字符的位置.
map.put(s.charAt(end),end);
}
return ans;
}
别人简简单单10多行代码就解决了问题,时间复杂度o(n)。
看来还是我太蠢了,继续加油,冲冲冲。