当前位置: 首页 > news >正文

Leetcode hot 100刷题之路(day 1)

两数之和

第一种解法:显而易见暴力解法 时间复杂度O(n^2)明显过高

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for(int i=0;i<nums.size();i++)
        {
            for(int j=i+1;j<nums.size();j++)
            {
                if(nums[i]+nums[j]==target)return {i,j};
            }
        }
        return {};
    }
};

第二种解法 可以用空间换时间 用哈希表存储数据,因为之前第一种解法每当遍历到一个数,都要判断一个个判断和之前的数相加是否为target。使用哈希表便只需要O(1)时间

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        mp[nums[0]]=0;
        for(int i=1;i<nums.size();i++)
        {
            if(mp.count(target-nums[i]))return{mp[target-nums[i]],i};
            else mp[nums[i]]=i;
        }
        return {};
    }
};

字母异位词分组

第一种做法:使用哈希,首先要给传入的字符串排序,如果排序后已经存在于哈希表了,那就存入。这题主要要注意的vector<vector<string>>如何存入 时间复杂度O(nklogk) n是字符串数量,k是字符串最大长度,需要klogk时间排序以及o(1)存入哈希表

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>> vec;
        int cnt=0;
        unordered_map<string,int> mp;
        for(int i=0;i<strs.size();i++)
        {
            string str=strs[i];
            sort(str.begin(),str.end(),less<char>());
            if(mp.count(str)!=1)
            {
                mp[str]=cnt++;
                vector<string> sts(1,strs[i]);
                vec.emplace_back(vector<string>{strs[i]});//emplace_back(sts)
            }//新开一个异位词列表
            else
            {
                vec[mp[str]].emplace_back(strs[i]);
            }
        }
        return vec;
    }
};

最长连续子序列

想要找到最长子序列,其实就是对每一个数x,查询数组中是否存在 x+1,如果有,再次查询是否有x+2.可以用哈希优化搜寻过程为O(1),但是,外层需要遍历n个数,内层也需要匹配O(n)次,但其中有可以优化的过程,如果x匹配过了 那么x+1就不需要再次判断,因为肯定比x匹配过的短。所以只需要对不存在x-1的x进行匹配即可,时间复杂度O(n).代码如下

基本知识:unordered_set无序,但查找单个元素快于set

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> st;
        for(auto &it:nums) st.insert(it);
        int max_num=0;
        for(auto &it:st)
        {
            if(st.count(it-1)==0)
            {
                int now_num=it+1;
                int now_length=1;
                while(st.count(now_num))
                {
                    now_num++;
                    now_length++;
                }
                max_num=max(max_num,now_length);
            }
        }
        return max_num;
    }
};

移动零

目的是让数组分为两个区域,非零区域和零区域。那么可以使用双指针来维护这两块区域,第一块区域是非零区,只需要一个双指针指向尾部+1的位置。第二块是待处理区域,待处理区域也用一个指针维护,两块区域之间就是零区域。当右指针指向非零,需要移动,不然会进入零区域,当指向零,不需要操作,只需要指向下一块区域。时间复杂度O(n)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int lp=0,rp=0;
        while(rp<nums.size())
        {
            if(nums[rp])
            {
                swap(nums[lp],nums[rp]);
                lp++;
            }
            rp++;
        }
    }
};

乘最多水的容器

利用双指针指向容器的两边。暴力的思想就是针对每一个点,遍历后面的所有点,时间复杂度O(n^2)明显过于复杂。我们利用双指针可以优化到O(n),面积是由长度*两者间最小的高度确定的。那么当缩短长度时,只有高度变高才有可能变大。所以我们每次只缩短高度低的那一侧指针即可。

class Solution {
public:
    int maxArea(vector<int>& height) {
        int lp=0,rp=height.size()-1;
        int max_num=0;
        while(rp>lp)
        {
            int high=min(height[lp],height[rp]);
            max_num=max(max_num,(rp-lp)*high);
            if(height[lp]<height[rp])lp++;
            else rp--;
        }
        return max_num;
    }
};

三数之和

其实也有点像双指针,都是利用两个指针来确定区域。如果这题直接做是O(n^3),考虑优化,先进行sort排序,空间复杂度O(logN)_递归调用。我们可以观察到,在最外层i确定之后,j增加,k只能减少。所以可以减少到O(n^2).而还有重要的一点,i和j必须保证和上一次不同。k不需要,因为i,j不同后,k必然不同.同时,这个保证不相同的代码必须要注意有没有超出上限

学习到的知识:代码要有鲁棒性,保证不会超出内存。emplace_back需要vector<int>{a,b,c}而push_back的插入只需要{a,b,c}.代码如下

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> vec;
        sort(nums.begin(),nums.end(),less<int>());
        for(int i=0;i<nums.size()-2;i++)
        {
            while(i>0&&nums[i]==nums[i-1]&&i<nums.size()-2)i++;
            int k=nums.size()-1;
            int target=nums[i]*-1;
            for(int j=i+1;j<nums.size()-1;j++)
            {
                while(j>i+1&&nums[j]==nums[j-1]&&j<nums.size()-1)j++;
                while(j<k&&nums[j]+nums[k]>target)
                {
                    k--;
                }
                if(j==k)break;
                if(nums[j]+nums[k]==target)vec.emplace_back(vector<int>{nums[i],nums[j],nums[k]});
            }
        }
        return vec;
    }
};

接雨水 典中典

第一种解法,维护双指针,分别在0,size()-1,维护两个变量,分别是左最高,右最高。每次只有这两个变量的最小值才能更新ans 时间复杂度O(n)

class Solution {
public:
    int trap(vector<int>& height) {
        int ans=0;
        int lp=0,rp=height.size()-1;
        int l_max=0,r_max=0;
        while(lp<rp)
        {
            l_max=max(l_max,height[lp]);
            r_max=max(r_max,height[rp]);
            if(l_max<r_max)
            {
                ans+=l_max-height[lp];
                lp++;
            }
            else
            {
                ans+=r_max-height[rp];
                rp--;
            }
        }
        return ans;
    }
};

做法2:直接一开局就搜寻每个点的leftmax和rightmax。然后遍历一遍就好,其实差不多

做法3:单调栈。这个想法挺好的


无重复字符最长子串

考虑字符串X1X2X3X4X5,当1-3均不重复,4出现重复,可能是任意一个1-3的字母,常规解法是从2开始继续遍历,但其实可以从4继续遍历。时间复杂度O(N)N为字符串长度,左右指针分别遍历了整个字符串一次。代码如下

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_set<char> st;
        int max_num=0;
        int rp=0;
        for(int i=0;i<s.size();i++)
        {
            if(i)st.erase(s[i-1]);
            while(rp<s.size()&&st.count(s[rp])!=1)
            {
                st.insert(s[rp]);
                rp++;
            }
            max_num=max(max_num,rp-i);
        }
        return max_num;
    }
};

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

特判一下大小。这道题用了数组的做法,判断两者的字母数组是否相同。

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int lens=s.size(),lenp=p.size();
        if(lens<lenp)return vector<int>();
        vector<int> scount(26,0);
        vector<int> pcount(26,0);
        vector<int >ans;
        for(int i=0;i<lenp;i++)
        {
            scount[s[i]-'a']++;
            pcount[p[i]-'a']++;
        }
        if(scount==pcount)ans.emplace_back(0);
        for(int i=1;i<lens-lenp+1;i++)
        {
            scount[s[i-1]-'a']--;
            scount[s[i+lenp-1]-'a']++;
            if(scount==pcount)ans.emplace_back(i);
        }
        return ans;
    }
};

其实也可以只用一个数组。s字符串中出现+1,p字符串中出现-1.如果都为0,那么便压入


和为K的子数组

暴力做法 超时O(n^2)

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        int count=0;
        for(int i=0;i<nums.size();i++)
        {
            int sum=0;
            for(int j=i;j<nums.size();j++)
            {
                sum+=nums[j];
                if(sum==k)count++;
            }
        }
        return count;
    }
};

前缀和+哈希表优化做法

其实就是连续子序列为k 即sum[i]-sum[j]=k我们只需要求出,到底有几个j就好,那么其实sum[j]=sum[i]-k,只要用map记录sum[j]的个数即可,时间复杂度O(n)

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int,int>mp;
        mp[0]=1;//因为可能k直接等于nums中某个元素
        int count=0,pre=0;
        for(auto& x:nums)
        {
            pre+=x;
            if(mp.find(pre-k)!=mp.end())count+=mp[pre-k];
            mp[pre]++;
        }
        return count;


    }
};

滑动窗口最大值

做法一,优先队列存储,加上一个存储下标的操作即可,用pair。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n=nums.size();
        priority_queue<pair<int,int>> q;
        for(int i=0;i<k;i++)q.emplace(nums[i],i);
        vector<int> ans={q.top().first};
        for(int i=k;i<n;i++)
        {
            q.emplace(nums[i],i);
            while(q.top().second<=i-k)q.pop();
            ans.emplace_back(q.top().first);
        }
        return ans;
    }
};

做法二 其实感觉以前写过类似的。开一个队列进行维护,由于前后都需要操作,所以开deque。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n=nums.size();
        deque<int> q;
        for(int i=0;i<k;i++)
        {
            while(!q.empty()&&nums[i]>=nums[q.back()])q.pop_back();
            q.emplace_back(i);
        }
        vector<int> ans={nums[q.front()]};
        for(int i=k;i<n;i++)
        {
            while(!q.empty()&&nums[i]>=nums[q.back()])q.pop_back();
            q.emplace_back(i);
            while(q.front()<=i-k)q.pop_front();
            ans.emplace_back(nums[q.front()]);
        }
        return ans;
    }
};

加油吧,还是刷的题不够多,思考也不够多,三月份其实已经尽我挺大程度的努力了。四月份继续加油,也没有几个月夏令营了 fighting~

http://www.dtcms.com/a/102411.html

相关文章:

  • 黑盒测试的场景法(能对项目业务进行设计测试点)
  • ngx_monotonic_time
  • Git Fetch 和 Git Pull 的区别
  • 双层板模组天线设计指南,50欧姆阻抗匹配设计
  • B-tree 索引失效 避坑指南
  • x265不同preset级别控制的编码参数与编码性能影响
  • BFS(广度优先搜索)
  • 使用DeepSeek API进行情感分析:超简单
  • c语言怎么处理字符串,与c++的区别
  • CentOS下安装Docker,Docker下安装JDK\MYSQL\REDIS\NGINX
  • 压测数据说话:如何用科学方法选择最优高防套餐?
  • 大数据技术之Scala:特性、应用与生态系统
  • MySQL - 索引原理与优化:深入解析B+Tree与高效查询策略
  • ‌粉笔屑里的星辰大海‌----灌南县第四中学九3班汤洁老师
  • harmony OS NEXT- HTTP 模块笔记
  • 【设计模式】享元模式
  • Transformer习题
  • 我开发了一款生成合成数据集的工具
  • 《C++ 函数相关技术解析》
  • 【Paper Tips】随记5-期刊投稿阶段说明
  • 低代码开发平台:企业数字化转型的加速器
  • Linux wifi 驱动移植适配流程详解
  • Java中如何保证高并发的数据安全
  • 高效定位 Go 应用问题:Go 可观测性功能深度解析
  • JavaScript弹出框的使用:对话框、确认框、提示框、弹窗操作
  • 智能体的核心模式和架构
  • [学术][人工智能] 001_什么是神经网络?
  • mapbox基础,使用geojson加载cluster聚合图层
  • leetcode994.腐烂的橘子
  • 使用 2 端口探头测量 40 uOhm(2000 安培)PDN 的挑战 – 需要多少 CMRR?