LeetCode 刷题 (五)(算法入门)

3.无重复字符最长子串

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

方法一:

锻炼一下自己的注释,可能有点啰嗦。嘿嘿嘿~~~

思路:每次添加一个字符到最长无重复串中,用 i,j标记该子串的首尾,然后遍历一遍去判断当前加入子串的元素有没有重复,如果重复,找到重复的位置,并更新子串首部。

class Solution {
public:
    //返回重复元素的位置,x表示当前最长子串的首部,y表示当前要加入最长子串的元素
    int Pos(string s,int x, int y){
        int pos=-1;  // -1表示没有重复元素
        while(x<y){
            //找到第一个重复元素的位置即可停止
            if(s[x]==s[y]){
                 pos = x;
                 break;
            }  
            x++;
        }
        return pos;
    }
    int lengthOfLongestSubstring(string s) {
        //每增加一个字符,就判断有没有重复
        int n = s.length();
        int ans=0;
        if(n==0)
            return ans;
        //i表示最长子串首部,j指当前及加入元素,flag标志是否更新首部    
        int i=0,j=0,flag=0;
        while(i<=j&&j<n){
            int pos = Pos(s,i,j);
            //更新头部
            if(pos!=-1)
                i=pos+1;
            //j-i+1当前最长串的长度    
            ans = max(ans,j-i+1);
            j++;
        }
        return ans;
    }
};

 时间复杂度:最坏情况,每次加入子串的元素都不重复,每次都要遍历整个子串,为O(n^2)

方法二:思路和上面的方法相同,不过在判断是否有重复元素,以及重复元素的位置时,可以选择用哈希表来更好更快的解决

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

时间复杂度:由于s仅被遍历一次,所以为O(N)

567.字符串的排列

LeetCode--567. 字符串的排列

本题的关键在于如何判读当前窗口中的s2的子串是s1一个排序。因为s1s2里面全是小写字母,我们可以用一个长度为26的数组表示每个子母出现的次数,当s2子串的长度与s1长度相等,且对应子母个数一样,此时即为一个排序。

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        int n = s1.length(),m = s2.length();
        if(n>m)
            return false;
        unsigned nums[26];
        for(unsigned i=0;i<26;i++){
            nums[i] = 0;
        }
        //在s2中取前与s1相同长度的字符,统计各个字母的个数是否相等
        for(int i=0;i<n;i++){
            nums[s1[i]-'a']--;
            nums[s2[i]-'a']++;
        }
        int diff=0;
        for(unsigned i=0;i<26;i++){
            if(nums[i]!=0)
                diff++;
        }
        if(diff==0)
            return true;
        for(int i=n;i<m;i++){
            //减去s2[i-n]=y,加入s2[i]=x
            int x = s2[i]-'a',y = s2[i-n]-'a';
            if(nums[x]==0)
                diff++;
            nums[x]++;
            if(nums[x]==0)
                diff--;

            if(nums[y]==0)
                diff++;
            nums[y]--;
            if(nums[y]==0)
                diff--;
            if(diff==0)
                return true;
        }
        return false;

    }
};

注:对于nums,s1里面含有的子母是做减法,表示当前还缺少那些子母,s2的子串是做加法。

同时,在移动窗口的时候,出窗口的子母个数要--,入窗口的子母个数要++。

时间复杂度:只需要遍历一次s2,所以为O(N)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值