6176. 出现最频繁的偶数元素 - 力扣(LeetCode)
桶思想,将所有的元素放入桶中统计,然后保存找到偶数出现次数最多是几次
然后再遍历桶,找到第一个为偶数且次数和最大次数相同的就立马返回,如果没有找到就返回-1
- const int N=110000;
- typedef pair<int,int> PII;
- class Solution {
- public:
- int mostFrequentEven(vector<int>& nums) {
- int h[N];
- memset(h,0,sizeof h);
-
- for(int i=0;i<nums.size();i++)
- h[nums[i]]++;
- int maxv=0;
- for(int i=0;i<N;i++)
- {
- if(i%2==0)
- maxv=max(maxv,h[i]);
- }
-
- for(int i=0;i<N;i++)
- {
- if(h[i]==maxv&&i%2==0&&h[i]!=0)
- {
- return i;
- }
- }
- return -1;
- }
- };
6177. 子字符串的最优划分 - 力扣(LeetCode)
双指针,类似于最长连续不重复子序列
- const int N=26;
- class Solution {
- public:
- int partitionString(string s) {
- int h[N];
- memset(h,0,sizeof h);
-
- int res=0;
-
- for(int i=0,j=0;i<s.size();)
- {
- while(j<s.size()&&h[s[j]-'a']==0)
- {
- h[s[j]-'a']++;
- j++;
- }
- memset(h,0,sizeof h);//记得清空
- i=j;
- res++;
- }
- return res;
- }
- };
6178. 将区间分为最少组数 - 力扣(LeetCode)
这题是个原题,代码和区间分组一模一样
遇到区间问题,第一个想法就是将左端点或者右端点排序,然后再模拟
这题是贪心,结论就是将左端点排序,然后再创建一个小根堆,如果该区间在这个组里面且该该区间的右端点比小根堆的右端点还小的话就放入堆中
如果发现区间没有交点就将堆顶删除再将该区间插入
最后组的个数就说堆中元素个数
- const int N=110000;
- struct Range{
- int l,r;
- bool operator<(const Range&t)const
- {
- return l<t.l;
- }
- }rang[N];
- class Solution {
- public:
- int minGroups(vector<vector<int>>& intervals) {
- int n=intervals.size();
- for(int i=0;i<n;i++)
- rang[i]={intervals[i][0],intervals[i][1]};
-
- sort(rang,rang+n);
-
- priority_queue<int,vector<int>,greater<int>> heap;
-
- for(int i=0;i<n;i++)
- {
- auto t=rang[i];
- if(heap.empty()||heap.top()>=t.l)heap.push(t.r);//如果和最小的r都有交点那就新开一个组
- else
- {
- heap.pop();//如果发现区间没有交点就替代堆顶的位置
- heap.push(t.r);
- }
- }
-
- return heap.size();
- }
- };
6206. 最长递增子序列 II - 力扣(LeetCode)
这题是很经典的最长上升子序列问题 ,用dp的方法做的话时间复杂度是O(n^2),一看数据范围是
10^5用dp做的话肯定会TLE,这就需要思考优化了,一开始我们学过一个优化贪心加二分能够将时间复杂度降低到O(nlogn)以内,但是这里比原来的最长上升子序列多了一个条件两个数之间只能相差k,所以不可以用二分,但是将dp的转移方程中f[i]=max(f[i],f[j]+1)中可以看出,我们要求出区间
j到i中最长的子序列长度,从这里可以看出是区间查询问题,然后单独一个数的最长上升子序列的长度是1,也就是单点修改,由此可以看出可以用线段树或者树状数组来写,线段树的查询和修改时间复杂度是(logn)能够有效的将时间控制在O(nlogn)以内
不过要注意的是,我们在线段树存储的区间 [l,r] 不再是原序列的下标,而是将数中的数值来作为线段树存储的区间,而查询的区间将会变成[x-k,x]查询出来就是在一个数相差不超过k的数中最长的上升子序列长度。
- const int N=110000;
-
- struct Node{
- int l,r;
- int v;
- }tr[N<<2];
-
- void push_up(int u)
- {
- tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
- }
-
- void build(int u,int l,int r)
- {
- tr[u]={l,r};
- if(l==r)return;
- int mid=l+r>>1;
- build(u<<1,l,mid),build(u<<1|1,mid+1,r);
- push_up(u);
- }
-
- void modfiy(int u,int x,int v)
- {
- if(tr[u].l==x&&tr[u].r==x)tr[u].v=v;
- else
- {
- int mid=tr[u].r+tr[u].l>>1;
- if(x<=mid)modfiy(u<<1,x,v);
- else modfiy(u<<1|1,x,v);
- push_up(u);
- }
- }
-
- int query(int u,int l,int r)
- {
- if (l > r) return 0;
- if(tr[u].l>=l&&tr[u].r<=r)return tr[u].v;
- int mid=tr[u].r+tr[u].l>>1;
- int mx=0;
- if(l<=mid)mx=query(u<<1,l,r);
- if(r>mid)mx=max(mx,query(u<<1|1,l,r));
- return mx;
- }
-
- class Solution {
- public:
- int lengthOfLIS(vector<int>& nums, int k) {
- int mx=0;
- for(int i=0;i<nums.size();i++)
- mx=max(mx,nums[i]);
-
- build(1,1,mx);
-
- for(auto t:nums)
- {
- int len=query(1,max(1,t-k),t-1);
- modfiy(1,t,len+1);
- }
-
- return query(1,1,mx);
- }
- };