给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/
示例1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是"wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串。示例 4:
输入: s = ""
输出: 0提示:
0 <= s.length <= 5 * 10^4
s由英文字母、数字、符号和空格组成
Java算法
思路:
- 先将问题拆分为 字符串拆分排列组合,以及字符串自身查重,
- 尝试运行后,发现计算超时,这里是暴力穷举
- 优化思路
- 无重复字符串最长,在找到相同长度时不再继续,转向更大位数查找
- 官方解更NICE
package sj.shimmer.algorithm;
import java.util.HashSet;
import java.util.Set;
/**
* Created by SJ on 2021/1/27.
*/
class D3 {
public static void main(String[] args) {
System.out.println(lengthOfLongestSubstring("abcabcbb"));
System.out.println(lengthOfLongestSubstring("bbbbb"));
System.out.println(lengthOfLongestSubstring("pwwkew"));
System.out.println(lengthOfLongestSubstring(""));
}
public static int lengthOfLongestSubstring(String string) {
if (string==null||string.length()==0) {
return 0;
}
int length = 1;
return Math.max(length,getCombination(string, 2));
}
public static int getCombination(String string, int sLength) {
if (string==null||string.length()<sLength) {
return 0;
}
for (int i = 0; i < string.length(); i++) {
int sub = sLength + i;
if (sub >string.length()) {
break;
}
String substring = string.substring(i, sub);
if (!hasRepait(substring)) {
return Math.max(sLength,getCombination(string,++sLength));
}
}
return 0;
}
public static boolean hasRepait(String string){
Set<Character> set = new HashSet();
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (set.contains(c)) {
return true;
}
set.add(c);
}
return false;
}
}

官方解
滑动窗口
在字符串中查找子串,相当于该子串的左右边界在字符串中根据条件滑动,来查找,类似与滑动窗口一样
左右指针遍历一次列表,省去大量循环
-
左边界 k,右边界k,右边界每轮中不停右移,左边界在停止或完成轮询时,右移
-
从第k个字符串开始查找,每次查找都将 字符添加至hashset,若移动到j+1有重复时表示找到了以k,j为始终位置的最长字符,就可以停止此轮遍历
-
下一轮则以k+1开始
以k+1开始时,k,j 不重复,k+1,j自然也不重复,所以只需从set中移除掉k位置的char即可,右边界则以j为开始移动 -
。。。
-
每轮记录比较最大值,即可得出
优点:相比较省去大量重复计算,时空优化很高,左右指针只遍历一次
时间复杂度:O(N),其中 N 是字符串的长度。左指针和右指针分别会遍历整个字符串一次。
空间复杂度:O(∣Σ∣),其中 Σ 表示字符集(即字符串中可以出现的字符),∣Σ∣ 表示字符集的大小。
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>(); // 哈希集合,用于判重
int length = s.length();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rightIndex = -1, resultLength = 0;
for (int i = 0; i < length; ++i) {
if (i != 0) {
set.remove(s.charAt(i - 1));// 左指针向右移动一格,移除一个字符;避免影响后续查重
}
while (rightIndex + 1 < length && !set.contains(s.charAt(rightIndex + 1))) {
// 不断地移动右指针
set.add(s.charAt(rightIndex + 1));
++rightIndex;
}
// rightIndex - i + 1为当前轮找到的最长长度(i为左指针)
resultLength = Math.max(resultLength, rightIndex - i + 1);
}
return resultLength;
}
网友评论