leetcode双周赛 45

A:水题,求数组中只出现一次的元素的和。

复制代码
 1 class Solution {
 2 public:
 3     int sumOfUnique(vector<int>& nums) {
 4         unordered_map<int,int> m;
 5         for(auto x:nums){
 6             m[x]++;
 7         }
 8         int res=0;
 9         for(auto x:m){
10             if(x.second==1){
11                 res+=x.first;
12             }
13         }
14         return res;
15     }
16 };
复制代码

B:找出子数组和的绝对值的最大值。

解法一:应用求最大子数组的双指针模型。

最终的答案要么是正数(非常大),要么是负数(非常小),应用两遍求最大子数组的双指针模型就可以求出答案。

复制代码
 1 class Solution {
 2 public:
 3     int maxAbsoluteSum(vector<int>& nums) {
 4         int n=nums.size();
 5         int l=0,r=0;
 6         int sum=0,res=0;
 7         while(r<n){
 8             sum+=nums[r];
 9             r++;
10             while(sum<0){
11                 sum-=nums[l];
12                 l++;
13             }
14             res=max(res,sum);
15         }
16         l=0,r=0;
17         sum=0;
18         while(r<n){
19             sum+=nums[r];
20             r++;
21             while(sum>0){
22                 sum-=nums[l];
23                 l++;
24             }
25             res=max(res,-sum);
26         }
27         
28         return res;
29     }
30 };
复制代码

解法二:利用前缀和

如果将原数组前缀和之后的话,就只需要枚举左右端点,但是时间上还是过不去。

然后发现如果此时我们求子数组最大值,那么对于每一个右端点i,我们需要知道的是1~i-1中的最小值。

如果求子数组的最小值,那么对于每一个右端点i,我们需要知道的是1~i-1中的最大值。

所以在前缀后之后,维护max_val,min_val就可以了。

复制代码
 1 class Solution {
 2 public:
 3     int maxAbsoluteSum(vector<int>& nums) {
 4         int n=nums.size();
 5         vector<int> s(n+1);
 6         for(int i=1;i<=n;i++){
 7             s[i]=s[i-1]+nums[i-1];
 8         }
 9         int max_val=0,min_val=0;//初始化为0是因为要求的是abs,所以不能初始化为无穷
10                                 //而初始化为0正好满足选择空数组的情况
11         int res=0;//初始状态就是选择空数组
12         for(int i=1;i<=n;i++){
13             res=max(res,abs(s[i]-max_val));
14             res=max(res,abs(s[i]-min_val));
15             max_val=max(max_val,s[i]);
16             min_val=min(min_val,s[i]);
17         }
18         return res;
19     }
20 };
复制代码

C:给定一个字符串,若左端点==右端点,那么可以将左边和右边大于一个的字符删除。求删除后的最短长度。

证明:如果删的话,一定尽可能地全部删掉。

    假设两边都不删完,那么下一次还是得删,所以不如删完。

    假设其中一边不删完,不妨设是左边,那么删完之后的字符串必定左端点不等于右端点,不如删完。

所以每次如果左端点等于右端点的话,直接删完就好了。

考试的时候的代码:

复制代码
 1 class Solution {
 2 public:
 3     int minimumLength(string s) {
 4         int begin=0,end=s.size()-1;
 5         while(s[begin]==s[end]&&begin<end){
 6             int l=begin,r=end;
 7             while(l<=end&&s[l]==s[begin]) l++;
 8             while(r>=begin&&s[r]==s[end]) r--;
 9             if(l>r) return 0;
10             begin=l,end=r;
11         }
12         return end-begin+1;
13     }
14 };
复制代码

更简洁的代码:

复制代码
 1 class Solution {
 2 public:
 3     int minimumLength(string s) {
 4         int i=0,j=s.size()-1;
 5         while(i<j){
 6             if(s[i]!=s[j]) break;
 7             char c=s[i];
 8             while(i<=j&&s[i]==c) i++;
 9             while(i<=j&&s[j]==c) j--;
10         }
11         return j-i+1;
12     }
13 };
复制代码

D:给定n个区间,每个区间有一个价值,选择k个不相交的价值最大的区间,返回最大价值。

 

 因为计算f [ i ] [ j ]的时候,需要找到右端点小于i左端点的最右边的那个区间。

所以我们可以将区间按照右端点排序,然后利用二分来寻找该区间。

这样的话时间复杂度为n*k*log n 

复制代码
 1 const int N=1e6+10;
 2 struct Q{
 3     int s,e,v;
 4     bool operator<(const Q& t){
 5         return e<t.e;
 6     }
 7 }q[N];
 8 class Solution {
 9 public:
10     int maxValue(vector<vector<int>>& events, int k) {
11         int n=events.size();
12         vector<vector<int>> f(n+1,vector<int>(k+1));
13         for(int i=1;i<=n;i++){
14             q[i]={events[i-1][0],events[i-1][1],events[i-1][2]};
15         }
16         sort(q+1,q+1+n);
17         for(int i=1;i<=n;i++){
18             for(int j=1;j<=k;j++){
19                 f[i][j]=f[i-1][j];//不选第i个
20                 int l=0,r=i-1;
21                 while(l<r){
22                     int mid=l+r+1>>1;
23                     if(q[mid].e<q[i].s) l=mid;
24                     else r=mid-1;
25                 }
26                 f[i][j]=max(f[i][j] , f[r][j-1]+q[i].v);
27             }
28         }
29         return f[n][k];
30     }
31 };
复制代码

 

posted on   greenofyu  阅读(40)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
历史上的今天:
2020-02-09 P2921 在农场万圣节(非递归的类似于记忆化搜索的巧妙方法||记忆化搜索||tarjan)
点击右上角即可分享
微信分享提示