1.题目要求
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke"是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
2.解答
有两种思路,一种是滑动窗口,另一种利用哈希集合。
1)滑动窗口
创建一个滑动窗口,其中 i 是窗口的起始位置,j 是窗口的结束位置, 使用哈希表来存储每个字符及其在字符串中的索引。
每遇到一个重复的字符时,更新 i 的位置到重复字符上一次出现位置下标+1,使窗口内没有重复的字符。同时更新 ans 以存储目前为止找到的最长子串的长度,ans的值为j-i+1。
gpt:
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int ans = 0;
// 定义一个 map 来存储字符到索引的映射
Map<Character, Integer> map = new HashMap<>();
// 用 i 指示滑动窗口的起始位置
for (int j = 0, i = 0; j < n; j++) {
// 如果字符 s[j] 在 map 中,更新滑动窗口的起始位置
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)) + 1, i);
}
// 更新答案和 map 中字符 s[j] 的索引
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j);
}
return ans;
}
}
2)哈希集合
我用了个比较暴力的方法,和滑动窗口的思想基本是一样的。
也是用i和j两个指针来标记最长子串的起始和结束的位置,起始位置i先不变,j向右遍历,对字符串中i和j之间的字符进行检验,如果有重复的字符,则将i的下标更新为重复元素的最早出现的位置下标,然后更新记录的子串长度,得到最大值。
具体代码如下:
力扣官方解答:
class Solution {
public int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set<Character> occ = new HashSet<Character>();
int n = s.length();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int rk = -1, ans = 0;
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.remove(s.charAt(i - 1));
}
while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1));
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1);
}
return ans;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/227999/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
官方解答的时间复杂度为O(N),空间复杂度O(∣Σ∣),其中 Σ 表示字符集(即字符串中可以出现的字符),具体可以看:
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/227999/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
我的方法:
class Solution {
public int lengthOfLongestSubstring(String s) {
int res = 0;
for(int i=0,j=0;j<s.length();j++){
int index = checkNoRepeat(s,i,j);
if(index != -1){
i=index +1;
}
res = Math.max(res,j-i+1);
}
return res;
}
private int checkNoRepeat(String s, int start, int end){
Set<Character> set = new HashSet<>();
for(int i = start; i <=end; i++){
Character value = s.charAt(i);
//已经存在,返回原来的值的下标
if(set.contains(value)){
for(int j=start;j<i;j++){
if(s.charAt(j) == value){
return j;
}
}
// return set.contains(value);
}
set.add(value);
}
return -1;
}
}
class Main{
public static void main(String[] args ){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
String s = sc.nextLine();
Solution solution = new Solution();
int length = solution.lengthOfLongestSubstring(s);
System.out.println(length);
}
}
}
提交截图: