引言
在深入探讨编程算法的过程中,一个历久弥新的问题——“无重复字符的最长子串”经常出现在各种编程竞赛和面试中。这个问题要求我们在给定字符串中找到最长的不包含重复字符的子串,并返回其长度。为了高效地解决这个问题,我们通常采用滑动窗口的方法,它能够在一次遍历中找出满足条件的最长子串,极大地提升了算法的效率。
leetcode-⽆重复字符的最⻓⼦串
问题描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长
子串 的长度。
示例:
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
解题思路
思路1:暴力解法
- 对于字符串中的每个字符,都尝试以其为起点,向后扩展寻找最长的不含重复字符的子串。
- 使用一个哈希表(或数组)来记录当前考察的子串中每个字符出现的次数。
- 如果发现某个字符已经出现过,则停止当前子串的扩展,并尝试下一个字符作为起点。
- 时间复杂度较高,为 O(n^2),其中 n 是字符串的长度。
思路2:滑动窗口,演示过程如下图所示
- 使用双指针来定义一个滑动窗口,左指针和右指针分别表示当前考察子串的起始位置和结束位置。
- 进窗口:随着右指针的向右移动,不断扩展子串,同时用一个哈希表来记录当前子串中每个字符出现的最新位置。
- 判断,出窗口:如果发现某个字符已经存在于哈希表中,并且其位置在左指针的右侧(即该字符在当前考察的子串中重复出现),则将左指针移动到该字符上一次出现的位置的下一个位置,以确保子串中没有重复字符。
- 更新结果:不断更新并记录遇到的最长子串的长度。
- 时间复杂度为 O(n),其中 n 是字符串的长度,因为每个字符最多被遍历两次(一次是右指针到达它,一次是左指针跳过它)。
代码实现
以下是使用思路1暴力解法,C++实现的代码示例:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.length();
int ret = 0;
for(int i=0; i<n; i++){
int hash[128] = {0};
for(int j=i; j<n; j++){
hash[s[j]]++;
if(hash[s[j]] > 1) break;
ret = max(ret , j-i+1);
}
}
return ret;
}
};
以下是使用思路2滑动窗口,C++实现的代码示例:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.length();
int ret = 0;
int left = 0,right = 0;
int hash[128] = {0};
while(right < n){
hash[s[right]]++;
while(hash[s[right]] > 1){
hash[s[left++]]--;
}
ret = max(ret , right - left + 1);
right++;
}
return ret;
}
};
这段代码通过滑动窗口和哈希表的高效结合,实现了对无重复字符最长子串长度的快速求解。