LeetCode_03 无重复最长子串
题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
知识点
- 字符串+子串
- 集合
- 滑动窗口
滑动窗口
滑动窗口是数组/字符串问题中常用的抽象概念。
窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)[i,j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。
可以把滑动窗口看成一个队列,向右滑动的时候,就是左边元素出队
子串
串中字符各不相同,则子串的个数为n(n+1)/2+1空串
如果串中有重复数字,则子字符串的个数为n(n+1)/2+1-重复个数
ublic char charAt(int index)
返回指定索引处的 char 值。索引范围为从 0 到 length() - 1。序列的第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推,这类似于数组索引。
如果索引指定的 char 值是代理项,则返回代理项值。
解法
思路一 暴力破解
逐个检查所有的子字符串,看它是否不含有重复的字符。
需要枚举给定字符串的所有子字符串
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
检查一个字符串是否有重复字符,我们可以使用集合。我们遍历字符串中的所有字符,并将它们逐个放入 set 中。在放置一个字符之前,我们检查该集合是否已经包含它。如果包含,我们会返回 false。循环结束后,我们返回 true。
//java
//代码注释来自于‘学习那些事’场外援助
public class Solution {
//返回长度
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++)//遍历整个字符串s
for (int j = i + 1; j <= n; j++)
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
//allUnique 会返回一个字符串是否含有重复字符,如果有返回false,没有返回true,而字符串便是s从i位置到j位置的字符
//故,如果当此子串没有喊有重复字符,其长度为j-i,math.max()则是,比较ans,和(j-i),并选择最大的返回,以保证ans时刻为最大的不重复字符串长度
return ans;
}
//检查一个字符串是否有重复字符
public boolean allUnique(String s, int start, int end) {
Set<Character> set = new HshSet<>();//?
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);//charAt返回指定i处的 char 值
if (set.contains(ch)) return false;//contains:判断集合是否包含ch
set.add(ch);
}
return true;
}
}
思路二 滑动窗口
#include <iostream>
#include <string>
using namespace std;
class Solution {
public:
// 查找是否重复,若有重复则返回重复数字下标,若没有重复,则返回-1
int isRepeat(string s, string sub) {
if (s.find(sub) == s.npos) {//没有重复;find返回字母sub在母串s中的位置(下标记录);npos表示不存在的位置
return -1;
}
else {
return s.find(sub);//重复数字下标
}
}
int lengthOfLongestSubstring(string s) {//定义函数lengthOfLongestSubstring返回最大不重复的位数
if (s.length() == 0 || s.length() == 1)//如果字符串长度是0或者1直接返回长度
return s.length();
int maxSize(1);//=1!全部重复的时候,长为1;用maxSize来记录不重复的字符串最长长度
string substring = s.substr(0, 1);//substr(0,1)从0开始向后截取一位,代表着字符串的第一位
for (int i = 1; i < s.length(); ++i) {
string temp = s.substr(i, 1);//substr(i,1)从i开始截取一位
int repeatPosit = isRepeat(substring, temp);//开始比较substr字符串和遍历第i字符串,如果有重复,返回数字下标
if (repeatPosit == -1) {//如果没有重复
substring.append(temp);//append直接在substring后面添加字符串temp(从i开始截取一位)
if (substring.length() > maxSize) {//把substring的长度直接返回给maxSize
maxSize = substring.length();
}
}
else {//如果有重复,repeatPosit是重复数字下标
substring.append(temp);//append直接在substring后面添加字符串temp(从i开始截取一位)
substring = substring.substr(repeatPosit + 1);//更换无重复字符串;substr截取了重复字符数字下标repeatPosit+1一直到结尾
}
}
return maxSize;
}
};
int main() {
Solution solution;
string s("asdf123"), s1("pwwkew");
cout << solution.lengthOfLongestSubstring(s) << endl;
cout << solution.lengthOfLongestSubstring(s1) << endl;
}