[贪心|字符串] leetcode 3 无重复字符的最长子串
1.题目
题目链接
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
示例1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
2.分析
2.1.子串与子序列
子串要求必须是连续的,而子序列不一定连续。例如在例3中,pwwkew的一个子序列是pwke,其并不连续。
2.2.如何判断“无重复”
本题的一个核心需要解决的问题在于如何判断一个子串无重复字符。
可以借助哈希表(hashset)这一数据结构,对于某个给定的字符串str,我们将str内每个字符逐个加入hashset中,利用count方法来判断当前字符是否已经在字符串中出现过。
for (int i = 0; i < n; i++) { //n为字符串长度
//遍历字符串直到出现重复字符
while (j + 1 < n && !_set.count(s[j + 1])) {
_set.insert(s[j + 1]);
j++;
}
}
2.3.如何获取子串
对于字符串str,子串substr(i, j)即为str中第i个到第j个之间的所有字符组成的字符串。因此,我们先解决i如何获取的问题。
i可以直接从0遍历到n-1(n为字符串长度)
从代码实现的角度来讲,子串(i + 1, j)可以通过删除子串(i, j)左侧的一个字符来实现。
for (int i = 0; i < n; i++) {
if (i != 0) {
_set.erase(s[i - 1]);
}
}
而对于j,由于本题目的为“寻找无重复子串”,因此可以让右指针j右移,直到发现有重复字符为止 (见2.2)。
3.代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set<char> _set; //存储当前子串内字符
int n = s.size();
int j = -1; //子串右指针j
int ans = 0;
for (int i = 0; i < n; i++) {
//左指针i右移,删除原串最左侧字符形成新串
if (i != 0) {
_set.erase(s[i - 1]);
}
//右指针j向右移动直到发现重复字符为止
while (j + 1 < n && !_set.count(s[j + 1])) {
_set.insert(s[j + 1]);
j++;
}
//子串长度为j - i + 1
ans = max(ans, j - i + 1);
}
return ans;
};
};