leetcode刷题——无重复字符的最长子串

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

【Python3实现】

例如,s="ababcdeff "中,最长子串“abcdef”长度为6;

简单分析:长度为 n 的字符串,有 n(n+1)/2 个子字符串 ,复杂度为 O(n*n), 判断长度为 n 的字符串是否有重复字符的次数是(1+2+3+4+5+6+...+ n-1),复杂度为O(n)。所以暴力法解决的复杂度为O(n*n*n)。

与队列类似,用到双指针。比如例题中的 ababcdeff,进入这个队列(窗口)为 ab 满足题目要求,当再进入 a,队列变成了 aba,这时候不满足要求。所以,j 要向右移动这个队列,利用指针 i+1 指向前一个重复字符的后面位置,即左指针指向b,计算队列长度 j-(i+1)+1 ,更新结果。所以关键在于如何判断重复和找到重复字符的下一个位置。

方法一:滑动窗口+哈希表

哈希表dic{ }统计:

指针 j 遍历字符,将每个字符和它的位置所组成的键值对录入dic{ }中,并在j遍历的时候,实时更新键值对,目的是利用哈希表统计字符 s[j] 的最后一次出现的索引(如果有重复,统计的索引就是前一个重复字符的位置),用于更新左指针i。

更新左指针i:

根据上一轮左指针 i 和dic,每轮更新左指针 i , 让区间 [i+1,j] 内无重复字符达到最大。更新方法,  i = max( dic[s[j]] , i )

更新结果 res:

取上一轮的res 和本轮双指针区间[i+1,j]的宽度(j-i)最大值。更新方法,res = max( res,j-i)

过程记录:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic, res, i = {}, 0, -1
        for j in range(len(s)):
            if s[j] in dic:
                i = max(dic[s[j]], i) # 更新左指针 i
            dic[s[j]] = j # 哈希表记录
            res = max(res, j - i) # 更新结果
        return res

复杂度分析:

时间复杂度O(n)        空间复杂度O(128)=O(1)

方法二:动态规划+哈希表

状态定义: 设动态规划列表 dp ,dp[j] 代表以字符 s[j]为结尾的 “最长不重复子字符串” 的长度。利用j 来遍历,设s[j] 左边距离最近的相同字符为s[i]

控制条件:dp[j-1] < j - i   dp[j]= dp[j-1]+1  ,(现在遍历的是没出现过的字符)                                                     dp[j-1] >= j - i  dp[j]= j-i  ,(当前遍历的是已经出现过的字符,移动指针i后的长度,就是当前的dp[j]的值)

用一个变量tmp来记下当前dp值

哈希表统计各字符最后一次出现的索引位置、遍历到s[j]时,可以通过访问哈希表dic[s[j]]获取最近相同字符的索引i.

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = {}
        res = tmp = 0
        for j in range(len(s)):
            i = dic.get(s[j], -1) # 获取索引 i,当前dic中没有s[j]的话,就返回-1
            dic[s[j]] = j # 更新哈希表
            tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]
            res = max(res, tmp) # max(dp[j - 1], dp[j])#dp是以s[j]为结尾的最长子串的长度
        return res

复杂度分析:

时间复杂度O(n)        空间复杂度O(128)=O(1)


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值