leetcode 3. 无重复字符的最长子串

题目描述

        初始化 ans for 初始化慢指针 = 0, 快指针 = 0 in 可迭代集合 更新窗口内信息 while 窗口内不符合维护的条件 扩展或者收缩窗口 慢指针移动 if 是合法的答案 更新答案 返回 ans 

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

思路一:

看到这道题我首先想到的是用Python的字典,C++的map来实现,先定义一个first指针指向-1,之后挨个遍历字符串,将遍历到的字符记录为Key值,Value为该字符在字符串中的位置,之后当遍历时只要有重复字符出现时,也就意味着相同的Key值要进入字典,此时将最先记录Key值的字符的Value值赋给first指针,就此时的状态而言,最长无重复子串=该字符在字符串中的位置-first指针所指的值(也就是该字符上一次在字符串中出现的位置),当每次字符串向后遍历一位时,都记录最长无重复子串的最大值,以此类推对最大值进行更新,求出最长无重复字符子串。

C++:

#include <unordered_map>
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> d;//无序map
        int first = -1,max = 0,n=s.size();
        for(int i=0;i<n;i++)
        {
            if (d.find(s[i])!=d.end() && d[s[i]]>first)//s[i]在map中存在且在字符串中的位置大于first指针
            {
                first= d[s[i]];//将原先该字符的value值赋给first指针
                d[s[i]] = i;//更新该字符现在的value值
            }
            else
                d[s[i]]= i;
                if (i-first >=max)
                {
                    max = i-first;
                }
        }

        return max;
    }
};

Python:

class Solution(object):
    def lengthOfLongestSubstring(self, s):
        first = -1
        max = 0 
        d = {}

        for i in range(len(s)):
            if s[i] in d and d[s[i]]>first:
                first = d[s[i]]
                d[s[i]] = i 
            else:
                d[s[i]] = i
                if  i - first >= max:
                    max = i -first
        return max

思路二(leetcode官方给的解法):滑动窗口(其实也是用了双指针)

大概意思是:始终保证左右指针之间的字符串为无重复子串,遍历字符串统计出最长的无重复子串

        难想的是左指针向右移动的时机,官方给的题解很巧妙,在每次大循环时,都会将左指针向右移动一格,那么问题的关键就变成了右指针停止的条件,即左指针所指的字符重复出现的时机。在什么情况下能直接判断出字符是否重复出现呢,对,是set容器!我们只要将每个统计过的字符加入了set容器,那么当set容器中存在的值再次出现时,我们便知道此时右指针该停止移动了,该左指针移动!

        所以便能写出关键代码:

 while (rk + 1 < n && !occ.count(s[r + 1])) {
                // 不断地移动右指针
                occ.insert(s[r + 1]);
                ++rk;
            }

从而写出完整代码:

C++

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_set<char> occ;//建立无序set容器
        int n=s.size();
        int r=-1;
        int ans =0;
        for (int i=0;i<n;i++)
        {
            if (i!=0){//将最左边元素出集合
              occ.erase(s[i-1]);  
            }
            while(r+1<n && !occ.count(s[r+1]))//右指针继续遍历条件
            {
                occ.insert(s[r+1]);//集合中加入右指针所指字符
                r++;
            }
            ans = max(ans,r-i+1);
        }
        return ans;
    }
};

Python:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        occ = set()
        n = len(s)
        r, ans = -1, 0
        for i in range(n):
            if i != 0:
                occ.remove(s[i - 1])
            while r + 1 < n and s[r + 1] not in occ:
                occ.add(s[r + 1])
                r += 1
            # 第 i 到 r 个字符是一个极长的无重复字符子串
            ans = max(ans, r - i + 1)
        return ans

总结:

        这道题只要理解了思路,不是很难做,难在思路和一些地方具体代码的实现。双指针在做数组,字符串,链表等问题时使用频率很高,需要熟练掌握。

涉及知识:双指针

                C++ :map容器, set容器

                Python: 字典 ,set()函数

相关问题可在我的专栏中查看:

双指针_小梁今天敲代码了吗的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小梁今天敲代码了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值