今天的签到题确实有点难了,想了很久没有实现,遂放弃,随便找了个中等难度的题目做。(毕竟还处于学习阶段,不能浪费太长时间~加上正好最近学到String类和相关类,就找了个字符串的题目做)老规矩链接如下:
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/这次的题目描述十分简单,基本不会存在任何歧义。
思路1:
直接想到就是递归。依次判断当前串是否无重复字符,如果是,返回当前串长度,否则将当前串开头去掉1个字符后继续判断,同时将结尾去掉1个字符后的子串继续判断,两者较大者为串的最长长度。
代码如下:
public static int lengthOfLongestSubstring(String s) {
if(s.length() <= 1){ //当长度小于等于1,递归结束
return s.length();
}
for(int i=0; i<s.length(); i++){
// 如果当前串存在重复字符则不是无重复子串
if(s.indexOf(s.charAt(i)) != s.lastIndexOf(s.charAt(i))){
// 判断开头去掉一个字符的子串是否符合
int leftLength = lengthOfLongestSubstring(s.substring(1));
// 判断最右面去掉一个字符的子串是否符合
int rightLength = lengthOfLongestSubstring(s.substring(0,s.length()-1));
// 将两者长度较长者长度返回
return Math.max(leftLength,rightLength);
}
}
// 出循环代表是无重复子串,返回长度
return s.length();
}
问题很大,效率极低,递归次数太多果不其然最后一个测试用例超时,开始其他方法。
思路2:
依旧是递归,但是在原有思路上减少递归次数,观察部分复杂用例,我们从字符串开头开始向右遍历,当出现带重复的子串时,记录目前不重复子串的长度,并从重复字符第一次出现的位置开始递归,与之前记录的长度比较,将将两者中较大者返回即可。递归次数大大减小,不过效率依旧较低,好歹满足需求了~代码如下:
package cn.daycode.leetcode;
public class LengthOfLongestSubstring {
public static void main(String[] args) {
String s = "dgaijvwcyaubwewpjvygehljxe";
System.out.println(lengthOfLongestSubstring(s));
}
public static int lengthOfLongestSubstring(String s) {
if(s.length() <= 1){
return s.length();
}
int firstIndex = 0;
for (int i = 0; i < s.length(); i++) {
// 当某个字符的下标不是第一次出现则为重复
if(s.indexOf(s.charAt(i)) != i){
// 记录一下当前字符第一次出现的位置,+1后作为递归函数参数子串的起始位置
firstIndex = s.indexOf(s.charAt(i));
// 将当前串长度与firstIndex下标开始的子串里最长无重复子串比较,返回较大者
return Math.max(i, lengthOfLongestSubstring(s.substring(firstIndex+1)));
}
}
return s.length();
}
}