力扣——第88场双周赛
6212. 删除字符使频率相同
问题解析
可以先记录下每个字符的出现次数,然后我们分情况讨论:
- 是否仅有一个字符的出现次数比其它的字符要多1,如果有,返回true。如果没有或者有多个,返回false;
- 是否有字符的出现次数和其它字符出现次数相差不止1,如果有,返回false;
- 是否所有的字符出现次数都是1,如果是,返回true;
- 是否只有一种字符,如果是,返回true。
AC代码
class Solution {
public:
unordered_map<char,int>mymap;
bool equalFrequency(string word) {
for(auto &i:word)
mymap[i]++;
int mn=0;
bool flag=true,st=true;
for(auto& i:mymap)
{
if(flag)mn=i.second,flag=false;
else if(mn!=i.second)
{
if(!st)return false;
else if(abs(mn-i.second)==1)
{
mn=min(mn,i.second);
st=false;
}
else return false;
}
}
if(st)
{
if(mn==1||mymap.size()==1)return true;
else return false;
}
return true;
}
};
6197. 最长上传前缀
问题解析
方便的做法:
用c++的set容器先将1~n的数都存起来,当上传哪个视频的时候,就在set中删除它。因为set自动排序的原因,最小的都在最前面,我们把set的第一个元素 - 1输出即可,如果set为空,输出n。
class LUPrefix {
public:
set<int>st;
int len;
LUPrefix(int n) {
len=n;
for(int i=1;i<=n;i++)st.insert(i);
}
void upload(int video) {
st.erase(video);
}
int longest() {
if(st.empty())return len;
return *st.begin()-1;
}
};
复杂的做法:
用线段树,每次给位置为i的位置赋值为1,然后询问的时候,在线段树上二分,找第一个0出现的位置x,答案就是x-1.
class LUPrefix {
public:
int f[4*100050];
int len;
void revise(int k,int l,int r,int x)
{
if(l==r)
{
f[k]=1;
return;
}
int m=(l+r)/2;
if(x<=m)revise(k+k,l,m,x);
else revise(k+k+1,m+1,r,x);
f[k]=f[k+k]+f[k+k+1];
}
int serch(int k,int l,int r)
{
if(l==r)return l;
int m=(l+r)/2;
if(f[k+k]!=m-l+1)return serch(k+k,l,m);
else return serch(k+k+1,m+1,r);
}
LUPrefix(int n) {
memset(f,0,sizeof f);
len=n;
}
void upload(int video) {
revise(1,1,len,video);
}
int longest() {
if(f[1]==len)return len;
return serch(1,1,len)-1;
}
};
6213. 所有数对的异或和
首先,我们知道异或的一个性质:如果一个数被异或了偶数次,那么就相当于没异或这个数。
然后我们看两个数组,nums1的元素要先和nums2的元素各异或一次,组成新数组,在计算新数组的异或和。
那么对于nums[i]来说,在新数组中,它提供的元素就有nums1[i]nums2[0],nums1[i]nums2[1],……nums1[i]^nums2[n-1]。如果这些数进行异或运算,就可以转化成n个nums1[i]的异或和,异或上整个nums2数组的异或和。那么,如果nums2数组长度为偶数,n个nums1[i]的异或和就相当于0,结果就是nums2数组的异或和。如果nums1也是偶数长度,就相当于偶数个nums2数组的异或和,答案为0。把nums1和nums2反过来也一样。
此时我们就可以分情况讨论了:
- 如果nums1数组和nums2数组都是偶数长度,答案为0
- 如果只有nums1数组是奇数长度,答案就是nums1数组的异或和。
- 如果只有nums2数组是奇数长度,答案就是nums2数组的异或和。
- 如果都是奇数长度,答案就是nums1数组的异或和异或上nums2的异或和。
AC代码
class Solution {
public:
int xorAllNums(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size(),m=nums2.size();
if(n%2==0&&m%2==0)return 0;
else if(n%2==0)
{
int res=0;
for(int i=0;i<n;i++)
{
res^=nums1[i];
}
return res;
}
else if(m%2==0)
{
int res=0;
for(int i=0;i<m;i++)
{
res^=nums2[i];
}
return res;
}
int res=0;
for(int i=0;i<n;i++)
{
res^=nums1[i];
}
for(int i=0;i<m;i++)
{
res^=nums2[i];
}
return res;
}
};
6198. 满足不等式的数对数目
问题解析
式子nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff,可以转化成nums1[i] - nums2[i] <= nums1[j] - nums2[j] + diff。
那么我们可以那nums2数组减去nums1数组来获得一个新的数组nums3,我们只要知道nums3[i]<=nums[j]+diff的个数即可。
我们可以用线段树,从左往右遍历数组,每次计算1到nums3[i]+diff的区间和,这就是这个数能提供答案。再把nums3[i]位置的值++。
要注意的是,nums3[i]可能为负数,此时这就不能直接把nums3[i]位置的值++。对此,我们可以对所有数加一个偏移量,把负数变成正数,把正数变成更大的正数。
AC代码
class Solution {
public:
typedef long long ll;
long long f[4*100050];
void revise(ll k,ll l,ll r,ll x)
{
if(l==r)
{
f[k]++;
return;
}
int m=(l+r)/2;
if(x<=m)revise(k+k,l,m,x);
else revise(k+k+1,m+1,r,x);
f[k]=f[k+k]+f[k+k+1];
}
ll calc(ll k,ll l,ll r,ll x,ll y)
{
if(l==x&&r==y)return f[k];
int m=(l+r)/2;
if(y<=m)return calc(k+k,l,m,x,y);
else
if(x>m)return calc(k+k+1,m+1,r,x,y);
else return calc(k+k,l,m,x,m)+calc(k+k+1,m+1,r,m+1,y);
}
long long numberOfPairs(vector<int>& nums1, vector<int>& nums2, int diff) {
memset(f,0,sizeof f);
long long n=nums1.size(),res=0;
for(int i=0;i<n;i++)
{
int x=nums1[i]-nums2[i]+diff+30050;
res+=calc(1,1,100000,1,x);
revise(1,1,100000,x-diff);
}
return res;
}
};