cpp刷题打卡记录27——无重复字符的最长子串 & 找到字符串中所有字母的异位词

无重复字符的最长子串

题目中需要注意的是,答案必须是子串的长度 ,那么就意味着是连续的,所有又可以用双指针的方法来进行求解。

cpp 复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        if(s.size() == 0){
            return 0;
        }
        unordered_set<char> s1;
        int result = 0;
        int left = 0;
        for(int right = 0; right<s.size(); right++){
            while(s1.find(s[right]) != s1.end()){  //s[right]在s1中找到
                s1.erase(s[left]);
                left++;
            }
            s1.insert(s[right]);
            result = max(result, right-left+1);
        }
        return result;
    }
};

找到字符串中所有字母异位词

超出时间限制:

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int plen = p.size();
        vector<int> result;
        sort(p.begin(), p.end());
        for(int i = 0; (i+plen)<=s.size(); i++){
            string sub = s.substr(i, plen);
            sort(sub.begin(), sub.end());
            if(sub == p){
                result.push_back(i);
            }
        }
        return result;
    }
};

这个用sort在进行比较,比较耗费时间,不过先sort再判断是否相等是一般解决字母异位的方法,如字母异位词分组

优化:

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> result;
        if(s.size() < p.size()){
            return result;
        }
        vector<int> plist(26);
        vector<int> slist(26);
        for(char ch : p){
            plist[ch - 'a']++;
        }
        int left = 0;
        for(int right = 0; right<s.size(); right++){
            slist[s[right]-'a']++;
            if(right-left+1 == p.size()){//滑动窗口体现在这里,每p的长度进行一次比较
                if(slist==plist){
                    result.push_back(left);
                }
                slist[s[left] - 'a']--;//别忘了还需要减掉。这样保证slist里面始终与p的大小是相符合的
                left++;
            }
        }
        return result;
    }
};

这个时间复杂度为O(n),双指针的方法用在这里很正常,比较新奇的一点是这个解法先定义了两个vector,然后利用字母出现的频次来判断是否异位,很巧妙。

和为k的子数组

这道题目同样可以用暴力解法进行求解,但是也会超时。

接下来来看前缀和+哈希表的解法:

cpp 复制代码
class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> map;
        int result = 0;
        int frontSum = 0;
        map[0] = 1;
        for(int num : nums){
            frontSum += num;
            
            if(map.find(frontSum - k) != map.end()){
                result += map[frontSum - k];
            }

            map[frontSum]++;
        }

        return result;
    }
};

前缀和很巧妙的可以只用遍历数组一次就可以得到,两个元素对应的前缀和相减就可以得到他们俩之间的元素的和。同时再创建一个unordered_map,其key为每个元素的前缀和,value为该前缀和出现的次数。需要注意的是map[0] = 1;因为可能出现仅一个元素就可满足。思路是:for循环计算每个元素所对应前缀和,然后找是否有两前缀和相减为k(也就是某一段数组的和为k),若有则算是找到了符合要求的子数组,加对应的次数。

根本是没有想到前缀和。

最大子数组和

cpp 复制代码
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==1){
            return nums[0];
        }
        int frontSum = 0;
        int minfrontSum = 0;
        int maxSum = INT_MIN;
        int result = 0;
        for(int i = 0; i<nums.size(); i++){
            frontSum += nums[i];
            maxSum = max(maxSum, frontSum-minfrontSum);
            minfrontSum = min(minfrontSum, frontSum);
        }
        return maxSum;
    }
};

我刚开始的错误思路:也是利用前缀和,但我是找了最大的前缀和和最小的前缀和,然后它俩相减就是最大和的连续子数组,只能通过部分测试用例。分析后发现这样对于连续负数的数组是错误的,考虑不够全面。所以应该是利用前缀和并且记录此前面的最小的前缀和.

本集心得:

自己写的全只能通过部分用例,哈哈,还是考虑的不够全面,哈哈

相关推荐
XuecWu32 小时前
原生多模态颠覆Scaling Law?解读语言“参数需求型”与视觉“数据需求型”核心差异
人工智能·深度学习·算法·计算机视觉·语言模型
We་ct2 小时前
LeetCode 69. x 的平方根:两种解法详解
前端·javascript·算法·leetcode·typescript·平方
一直不明飞行2 小时前
C++:string,写法s.find(‘@‘) != s.end()是否有问题
开发语言·c++·算法
Proxy_ZZ02 小时前
打造自己的信道编码工具箱——Turbo、LDPC、极化码三合一
c语言·算法·信息与通信
wayz112 小时前
21天机器学习核心算法学习计划(量化方向)
学习·算法·机器学习
qq. 28040339842 小时前
数据结构引论
前端·数据结构
穿条秋裤到处跑2 小时前
每日一道leetcode(2026.04.09):区间乘法查询后的异或 II
算法·leetcode
超级大只老咪2 小时前
一维度前缀和解题通用模板(java)
java·开发语言·算法
无限进步_2 小时前
【C++】重载、重写和重定义的区别详解
c语言·开发语言·c++·ide·windows·git·github