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

题目如下:

当时脑子抽了没有看到下面的规定

 

也就是说,除了英文字母,还有数字和字符串、符号、空格。刚开始以为只有英文,就用了哈希表法做,通过了800多个案例,有100个没通过才意识到自己大概是看漏条件了。

方法一 仅提供思路 map表键值对

下面是我用哈希表法解题的思路,这个方法也可以扩展到所有字符,只需要把表扩展就行了,我只是记录一下这种思路,以下代码并不是答案。

class Solution {
public:
    int lengthOfLongestSubstring(string s){
    int len=0;//记录目前最长字串长度
    int len2=0;//记录当前字符串长度
    map<int,int> mp;//记录当前存在的字符
    for(int i=0;i<26;i++){
        mp[i]=-1;//如果当前字串没有出现该字符,默认为-1
    }    
    for(int i=0;i<s.size();i++){
       if(len<len2){
           len=len2;//如果当前字符长度大于最长,最长长度改变
       }
       char zifu=s[i];//当前字符
       if(mp[zifu-'a']==-1){//判断当前字符是否在字串中出现,未出现
           mp[zifu-'a']=i;//设置出现的先后顺序
           len2++;//当前字串长度+1
           continue;
       }else{
           int num=mp[zifu-'a'];//记录下重复字串的位置
           for(int j=0;j<26;j++){
               if(mp[j]!=-1&&mp[j]<=num){//在其前面的字串全部改为未出现
                   len2--;
                   mp[j]=-1;
               }
           }
           mp[zifu-'a']=i;//将当前字符存入
           len2++;
       }
    }
    return len;
}
};

     方法二 滑动窗口

 代码可以改进,但发现解法中用的滑动窗口,而且更简单,便直接去学习新方法了。官方解答如下:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

unordered_set是STL的一种容器,具体使用可以参考以下文章c++ unordered_set详细操作_好人好事代表nxx的博客-CSDN博客

      具体思路如下:在字符串左边同时放左指针和右指针,右指针不断向右移动,并将遇到的字符加入到unordered_set容器中。当unordered_set容器中出现两个相同元素时,左指针移动,不断删除元素,直到不存在两个相同元素为止。而后继续移动右指针,循环往复。在这过程中,记录下unordered_set容器的最大值,该最大值也就是不重复字串的最大值。

方法三 动态规划

该问题如果一直从左往右(或从右往左),可以拆解为一个一个的子问题进行分析。假设为从左往右,毫无疑问,第一个最大字串就是最左边元素,长度记为1。

从左往右遇到第二个字符,会出现两种情况:1.其与第一个元素相同2.与第一个元素不同

一直推,直到第n个元素,也同样是两种情况:

1.第n个元素向左的最大字串与第n-1个元素的最大字串不存在重复元素,其最大字串也就是第n-1个元素的最大字串加一。

2.第n个元素向左的最大字串与第n-1个元素的最大字串存在重复元素,第n个元素向左的最大字串要重新计算。

如下是我自己编写的使用动态规划的代码,该代码使用了辅助数组,利用第n-1项得到的答案去推算第n项的答案。动态规划构思也非常巧妙,我也是参考了左程云老师的思路。

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    int maxlength=1;
    if(s==" ")//特例
        return 1;
    if(s=="")//特例
        return 0;
    int p[s.size()];//辅助数组,记录第n-1个字符的最大不重复字串
    int tag=0;
    p[0]=1;
    for(int i=1;i<s.size();i++){//从左向右,当前位置为i
       for(int j=i-p[i-1];j<i;j++){//看第i-1的的最大字串是多少(p[i-1]),并从i-p[i-1]一直到i-1查看有没有与s[i]重复的字串,有的话重新计算,没有的话直接+1.
           if(s[i]==s[j])//存在重复串,该重复串的下标为j
           {tag=1;//标记
           p[i]=i-j;//记录下第n个字符的不重复字串最大长度
           maxlength=max(maxlength,p[i]);
           }
       }
       if(!tag){//没有重复串
           maxlength=max(p[i-1]+1,maxlength);//最大长度为当前最大长度,或最新的
           p[i]=p[i-1]+1;//记录下第n个字符的不重复字串最大长度
       }
    tag=0;
    }
    return maxlength;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值