LeetCode算法题:无重复字符的最长字串

题目描述:

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

示例 1:

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

示例 2:

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

示例 3:

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

题目解析:这道题不能用暴力法循环,会超时,但是我还是会贴出暴力法的代码,虽然过不了,但是比较好理解。这道题我是用滑动窗口做的,对于滑动窗口,下面引用LeetCode官方题解的描述:

滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)[i,j)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)[i,j)向右滑动 11 个元素,则它将变为 [i+1, j+1)[i+1,j+1)(左闭,右开)。

下面给出暴力法的C++代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int len=s.length();
        int cnt=0,i,j,k,flag=0,result[len+5];
        string x;
        int MAX=0;
        if(s==""){return 0;}
        if(s.length()==1){return 1;}
        for(i=0;i<len;i++){
            x = "";
            for(j=i;j<len;j++){
                flag = 0;
                for(k=0;k<x.length();k++){
                    if(s[j]==x[k]){flag=1;break;}
                }
                if(flag==0){x = x + s[j];}
                if(j==s.length()-1||flag==1){
                    result[cnt++]=x.length();
                    break;
                }
            }
        }
        for(i=0;i<cnt;i++){
            if(result[i]>MAX){MAX=result[i];}
        }
        return MAX;
    }
};

对于暴力法,我想官方的描述很恰当:

假设我们有一个函数 boolean allUnique(String substring) ,如果子字符串中的字符都是唯一的,它会返回 true,否则会返回 false。 我们可以遍历给定字符串 s 的所有可能的子字符串并调用函数 allUnique。 如果事实证明返回值为 true,那么我们将会更新无重复字符子串的最大长度的答案。

暴力法的时间复杂度是非常糟糕的O(n^3),所以会超时,下面给出利用滑动窗口写的C++和python代码:

C++完整代码如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int i = 0,j = 0, n = 0, ans= 0;
        set<char> cont;//定义一个set类型的变量
        n = s.size();
        set<char>::iterator iter;//定义一个set类型的迭代器
        
        while(i< n && j<n){          
            if( (iter=cont.find(s[j])) != cont.end() ){//如果迭代器所存储的字符存在于滑动窗口中,i向后移动一位
                cont.erase(s[i++]);    
            }
            else { //如果不在,j向后移动一位
                cont.insert(s[j++]);
                ans = max(ans, j-i);//获取最长的字串的长度
            }
            
        }
        return ans;//返回最终结果
    }
};

       可能会有朋友对if后面的判断条件有所疑惑,这里给出我的理解:set类型的find函数会返回一个迭代器(find的参数是你想要寻找的变量),如果找到,返回非空的迭代器,如果未找到,返回空值,而end()函数返回的也是空值,所以if的判断条件的意思是,如果find函数返回的不是空值(即end()函数的返回值),那么说明在子串中找到了这个字符,“窗口”的左边界向右移动一位。

代码执行结果:

执行用时 : 76 ms, 在Longest Substring Without Repeating Characters的C++提交中击败了31.23% 的用户

内存消耗 : 15.9 MB, 在Longest Substring Without Repeating Characters的C++提交中击败了42.30% 的用户

Python完整代码如下:

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        n = len(s)
        i = 0
        j = 0
        ans = 0
        it = ""
        cont = ""
        while i<n and j<n:
            if s[j] not in cont:
                cont += s[j]
                j += 1
                ans = max(ans,len(cont))
            else:
                cont = cont[i+1:]
        return ans

python用的也是滑动窗口,这里就不详细解释了。

代码执行结果:

执行用时 : 112 ms, 在Longest Substring Without Repeating Characters的Python3提交中击败了67.45% 的用户

内存消耗 : 13 MB, 在Longest Substring Without Repeating Characters的Python3提交中击败了98.17% 的用户

如果有写的不对的地方,还请各位朋友批评指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值