力扣 第159场双周赛(A~C)

A.最小相邻交换至奇偶交替

给一个数组,一次操作能够将相邻两个元素互换,问最少多少次操作之后,能够使得数组奇偶相间。

首先我们考虑我们的目标序列该是什么样子,当我们在某个位置需要一个特定的奇数或者偶数时,我们肯定是拿最近的来填,所以我们按顺序将数组分成奇偶两个,然后从这两个数组中一边拿一个就构成了我们最终的目标序列。

当然,其中有一些细节,比如元素总数为偶数,我们需要考虑起始为奇数和偶数的情况,若元素总数为奇数,那么我们肯定是只能以更多的那个为起始,若奇数偶数之差大于等于2,则不存在目标序列。

那么现在的问题就变成了,从一个序列,到目标序列,最少需要多少次相邻交换,这个问题和逆序对数量是高度匹配的,所以我们提取目标序列的序号,然后求一遍逆序对,即为目标序列转换为原始序列的操作次数。

 1 class Solution {
 2 public:
 3     vector<int> back;
 4     int ans;
 5     vector<int> make_v(vector<int> t1,vector<int> t2){
 6         vector<int> res;
 7         int i=0,j=0;
 8         while(i<t1.size()||j<t2.size()){
 9             if(i<t1.size()) res.push_back(t1[i++]);
10             if(j<t2.size()) res.push_back(t2[j++]);
11         }
12         return res;
13     }
14     
15     //求逆序对数目,merge_sort
16     void get(vector<int>& q,int l,int r){
17         if(l>=r) return ;
18         int mid=l+r>>1;
19         get(q,l,mid);
20         get(q,mid+1,r);
21         int i=l,j=mid+1,k=l;
22         while(i<=mid&&j<=r){
23             if(q[i]<=q[j]) back[k++]=q[i++];
24             else{
25                 back[k++]=q[j++];
26                 ans+=mid-i+1;
27             }
28         }
29         while(i<=mid) back[k++]=q[i++];
30         while(j<=r) back[k++]=q[j++];
31         for(int k=l;k<=r;k++){
32             q[k]=back[k];
33         }
34     }
35     int minSwaps(vector<int>& nums) {
36         int n=nums.size();
37         back.resize(n);
38         vector<int> v0,v1;
39         for(int i=0;i<nums.size();i++){
40             if(nums[i]%2==0) v0.push_back(i);
41             else v1.push_back(i);
42         }
43         int n0=v0.size(),n1=v1.size();
44         if(abs(n0-n1)>=2) return -1;
45         int res=INT_MAX;
46         if(nums.size()%2==1){
47             if(v0.size()<v1.size()) swap(v0,v1);
48             vector<int> t;
49             int i=0,j=0;
50             vector<int> v=make_v(v0,v1);
51             ans=0;
52             get(v,0,v.size()-1);
53             res=min(res,ans);
54         }else{
55             vector<int> tmp1=make_v(v0,v1);
56             vector<int> tmp2=make_v(v1,v0);
57             ans=0;
58             get(tmp1,0,tmp1.size()-1);
59             res=min(res,ans);
60             
61             ans=0;
62             get(tmp2,0,tmp2.size()-1);
63             res=min(res,ans);
64         }
65         return res;
66     }
67 };

B.找到最大三角形面积

给定坐标系上n个点,问底边与坐标轴平行的最大三角形面积是多少,为避免除以2,返回三角形面积的两倍。

三角形面积为底乘高,高可用min和max来维护,比如要求一个底与y轴平行,位于x=2的,底为base的三角形的最大面积,那么显然S=max(x-minx,maxx-x)*base。

那么我们需要维护三角形的底最大为多少即可。

 1 typedef long long LL;
 2 class Solution {
 3 public:
 4     long long maxArea(vector<vector<int>>& cor) {
 5         int n=cor.size();
 6         if(n<3) return -1;
 7         int minx=INT_MAX,maxx=INT_MIN;
 8         int miny=INT_MAX,maxy=INT_MIN;
 9         map<int,pair<int,int>> xg,yg;//xg[x]为当前x值下,最大的y值和最小的y值分别是多少
10         for(int i=0;i<n;i++){
11             int x=cor[i][0],y=cor[i][1];
12             minx=min(minx,x);
13             maxx=max(maxx,x);
14             miny=min(miny,y);
15             maxy=max(maxy,y);
16             if(!xg.count(x)) xg[x]={y,y};
17             else{
18                 xg[x].first=min(xg[x].first,y);
19                 xg[x].second=max(xg[x].second,y);
20             }
21             if(!yg.count(y)) yg[y]={x,x};
22             else{
23                 yg[y].first=min(yg[y].first,x);
24                 yg[y].second=max(yg[y].second,x);
25             }
26         }
27         LL ans=-1;
28         for(auto [x,yrange]:xg){
29             LL base = yrange.second-yrange.first;//底边长
30             if(base==0) continue;
31             LL height = max(x-minx,maxx-x);
32             ans=max(ans,base*height);
33         }
34         for(auto [y,xrange]:yg){
35             LL base = xrange.second-xrange.first;
36             if(base==0) continue;
37             LL height = max(y-miny,maxy-y);
38             ans=max(ans,base*height);
39         }
40         if(ans==0) return -1;
41         return ans;
42     }
43 };

 C.计数质数间隔平衡子数组

给定一个数组,问有多少个子数组满足其中至少两个质数,而且最大的质数减去最小的质数小于等于k。

显然,当子数组的右端点右移时,左端点要不保持不动,要不跟着右移,所以可以用双指针来解决这个问题。

再维护当前子数组的最大质数和最小质数,即可O(1)判断小于等于k,再维护一个质数队列。

 1 const int N = 5e4+10;
 2 class Solution {
 3 public:
 4     vector<bool> primes;
 5     void init(){
 6         primes.resize(N);
 7         for(int i=2;i<N;i++){
 8             if(primes[i]==false)
 9                 for(int j=i+i;j<N;j+=i)
10                     primes[j]=true;
11         }
12     }
13     bool isprime(int x){
14         if(x<=1) return false;
15         return !primes[x];
16     }
17     int primeSubarray(vector<int>& nums, int k) {
18         init();
19         deque<int> maxx,minn,p;
20         int i=0;
21         int n=nums.size();
22         int res=0;
23         for(int j=0;j<n;j++){
24             if(isprime(nums[j])){
25                 while(!maxx.empty()&&nums[maxx.back()]<=nums[j]) maxx.pop_back();
26                 maxx.push_back(j);
27                 while(!minn.empty()&&nums[minn.back()]>=nums[j]) minn.pop_back();
28                 minn.push_back(j);
29                 p.push_back(j);
30                 while(!maxx.empty()&&!minn.empty()&&i<=j&&
31                         nums[maxx.front()]-nums[minn.front()]>k){
32                     i++;
33                     while(!maxx.empty()&&maxx.front()<i) maxx.pop_front();
34                     while(!minn.empty()&&minn.front()<i) minn.pop_front();
35                     while(!p.empty()&&p.front()<i) p.pop_front();
36                 }
37             }
38             if(p.size()>=2){
39                 int t=p[p.size()-2];
40                 res+=t-i+1;
41             }
42         }
43         return res;
44     }
45 };

 

posted on 2025-06-22 13:33  greenofyu  阅读(10)  评论(0)    收藏  举报