力扣 第177场双周赛(A~D)

A:3852. 不同频率的最小数对
给定一个数组,要求这个数组中频率不同的最小的两个数。

这个数组中的min是必选的,可由反证法证。假设ans=[a,b],二者都不为min,且freq(a)!=freq(b),那么一定可以将其中一个数替换为min,同样满足频率不同。

必须min,那么O(n)找另一个数即可。

 1 class Solution {
 2 public:
 3     vector<int> minDistinctFreqPair(vector<int>& nums) {
 4         int minn=*min_element(nums.begin(),nums.end());
 5         map<int,int> cnt;
 6         for(int x:nums)
 7             cnt[x]++;
 8         for(auto [k,v]:cnt){
 9             if(v!=cnt[minn]){
10                 return {minn,k};
11             }
12         }
13         return {-1,-1};
14     }
15 };

B:3853. 合并靠近字符

合并距离小于等于k的相同字符,合并之后,会改变原有的字符串。

 1 class Solution {
 2 public:
 3     string mergeCharacters(string s, int k) {
 4         string ans="";
 5         map<char,int> last;
 6         //ans.size()表示当前s[i]放到的位置
 7         for(int i=0;i<s.size();i++){
 8             if(!last.count(s[i])||ans.size()-last[s[i]]>k){
 9                 last[s[i]]=ans.size();
10                 ans+=s[i];
11             }
12         }
13         return ans;
14     }
15 };

C:3854. 使数组奇偶交替的最少操作
问题分两问,首先问多少次操作能够使得数组变为奇偶交替,这一问比较简单,可以直接确定第一个元素的奇偶,然后O(n)比对即可。

第二问问在第一问的操作下,最小的max-min的值为多少,我们可以将一个可以改的元素x,看成x-1和x+1的列表,然后排序,找出最小的区间覆盖全部元素,具体可见力扣632题。

 

 1 typedef pair<int,int> PII;
 2 class Solution {
 3 public:
 4     vector<int> fun(int mode,vector<int>& nums){
 5         int n=nums.size();
 6         int ans1=0;
 7         vector<PII> v;
 8         //第一问,同时处理好第二问的数据
 9         for(int i=0;i<n;i++){
10             if((nums[i]&1)!=mode){
11                 ans1++;
12                 v.push_back({nums[i]-1,i});
13                 v.push_back({nums[i]+1,i});
14             }else{
15                 v.push_back({nums[i],i});
16             }
17             mode^=1;
18         }
19 
20         //第二问
21         sort(v.begin(),v.end());
22         int empty=n;
23         int l=0;
24         int ans2=INT_MAX;
25         vector<int> cnt(n,0);
26         for(int r=0;r<v.size();r++){
27             int val=v[r].first,id=v[r].second;
28             if(cnt[id]==0){
29                 empty--;
30             }
31             cnt[id]++;
32             while(empty==0){
33                 ans2=min(ans2,val-v[l].first);
34                 if(cnt[v[l].second]==1)
35                     empty++;
36                 cnt[v[l].second]--;
37                 l++;
38             }
39         }
40         return {ans1,ans2};
41     }
42     vector<int> makeParityAlternating(vector<int>& nums) {
43         vector<int> a=fun(0,nums);
44         vector<int> b=fun(1,nums);
45         if(a[0]==b[0])
46             return {a[0],min(a[1],b[1])};
47         else if(a[0]<b[0])
48             return a;
49         else
50             return b;
51     }
52 };

 D:3855. 给定范围内 K 位数字之和
要求L-R的数字组合出的所有k位数字的和,可用贡献法。

设k为数的从低位数的第i位数为x,那么有一个这个的贡献即为x*10i,再乘以有多少个k为数即可求出这一位数字为x的贡献,其他位并无限制,所以有(r-l+1)k-1个。

所以这一位的贡献为∑∑(x*10i)*(r-l+1)k-1,两个求和分别对x和i,x的值为L~R,用等差数列求和,i的值为0~k-1,用等比数列求和。

可得ans=1/18 * (L+R)*(R-L+1)k*(10k-1),此处为模,需要求逆元,1e9+7为素数,所以可用费马小定理。

 1 const int mod=1e9+7;
 2 class Solution {
 3 public:
 4     int ksm(int a,int b){
 5         int res=1;
 6         while(b){
 7             if(b&1)
 8                 res=1ll*res*a%mod;
 9             a=1ll*a*a%mod;
10             b>>=1;
11         }
12         return res;
13     }
14     int sumOfNumbers(int l, int r, int k) {
15         return 1ll*ksm(18,mod-2)*(l+r)%mod*ksm(r-l+1,k)%mod*(ksm(10,k)-1)%mod;
16     }
17 };

 

posted on 2026-03-05 13:36  greenofyu  阅读(17)  评论(0)    收藏  举报