第 73 场双周赛
题目
6024.数组中紧跟 key 之后出现最频繁的数字
题目大意
给你一个下标从 0 开始的整数数组 nums
,同时给你一个整数 key
,它在 nums
出现过。
统计 在 nums
数组中紧跟着 key
后面出现的不同整数 target
的出现次数。换言之,target
的出现次数为满足以下条件的 i
的数目:
0 <= i <= n - 2
nums[i] == key
且nums[i + 1] == target
。
请你返回出现 最多 次数的 target
。测试数据保证出现次数最多的 target
是唯一的。
样例
数据规模
思路
太久没做题和打比赛了。第一题就WA了两次。
一开始题读错了:意外只要 t a r g e t target target在 k e y key key之后就可以了,没有意识到两个必须挨着。
考虑使用map<int,int>mp
,记录所有元素的数量,然后遍历nums
保证nums[i]==key
,然后取出现数量最多的nums[i+1]
,它就是所要求的target
。
代码
class Solution {
public:
int mostFrequent(vector<int>& nums, int key) {
map<int,int>mp;
for(auto it:nums){
mp[it]++;
}
int opt=0,maxx=0;
for(int i=0;i<nums.size();i++){
if(nums[i]==key){
if(i+1<nums.size()&&maxx<mp[nums[i+1]]){
maxx=mp[nums[i+1]];
opt=nums[i+1];
}
}
}
return opt;
}
};
题目
5217.将杂乱无章的数字排序
题目大意
给你一个下标从 0 开始的整数数组 mapping
,它表示一个十进制数的映射规则,mapping[i] = j
表示这个规则下将数位 i
映射为数位 j
。
一个整数 映射后的值 为将原数字每一个数位 i
(0 <= i <= 9
)映射为 mapping[i]
。
另外给你一个整数数组 nums
,请你将数组 nums
中每个数按照它们映射后对应数字非递减顺序排序后返回。
注意:
- 如果两个数字映射后对应的数字大小相同,则将它们按照输入中的 相对顺序 排序。
nums
中的元素只有在排序的时候需要按照映射后的值进行比较,返回的值应该是输入的元素本身。
样例
数据规模
思路
这一题又WA了一次:原因是在进行数字分解的时候没有考虑 0 0 0的情况。
定义了一个结构体Node
用来记录原来的值p
,出现的下标位置id
和映射之后的值w
。
定义排序顺序:将数组 nums
中每个数按照它们映射后对应数字非递减顺序排序,如果两个数字映射后对应的数字大小相同,则将它们按照输入中的 相对顺序 排序。
然后将nums
中的数字进行分解并且映射,存储到Node
数组中,进行排序,然后直接返回排序之后的结果即可。
代码
struct Node{
int w,id,p;
};
bool cmp(Node x,Node y){
if(x.w==y.w)return x.id<y.id;
return x.w<y.w;
}
class Solution {
public:
Node a[30000+50];
vector<int> sortJumbled(vector<int>& mapping, vector<int>& nums) {
int cnt=0;
for(auto it:nums){
vector<int>b;
int x=it,y=0;
if(it==0){
cnt++;
a[cnt].id=cnt;a[cnt].w=mapping[0];a[cnt].p=it;
continue;
}
while(x){
int q=x%10;
x/=10;
b.push_back(q);
}
for(int i=b.size()-1;i>=0;i--){
int q=mapping[b[i]];
y=y*10+q;
}
cnt++;
a[cnt].id=cnt;a[cnt].w=y;a[cnt].p=it;
}
sort(a+1,a+1+cnt,cmp);
vector<int>ans;
for(int i=1;i<=cnt;i++)ans.push_back(a[i].p);
return ans;
}
};
题目
5300.有向无环图中一个节点的所有祖先
题目大意
给你一个正整数 n
,它表示一个 有向无环图 中节点的数目,节点编号为 0
到 n - 1
(包括两者)。
给你一个二维整数数组 edges
,其中 edges[i] = [fromi, toi]
表示图中一条从 fromi
到 toi
的单向边。
请你返回一个数组 answer
,其中 answer[i]
是第 i
个节点的所有 祖先 ,这些祖先节点 升序 排序。
如果 u
通过一系列边,能够到达 v
,那么我们称节点 u
是节点 v
的 祖先 节点。
样例
数据规模
思路
极限情况也就是 1000 1000 1000个点,不超过 2000 2000 2000条边,直接考虑每一个点 i i i出发能到达哪些点。
具体怎么考虑呢?
比如条件给定了有向边 a − > b a->b a−>b,那么就说明 a a a是 b b b的祖先,那么我们建边就可以反向考虑建边 b − > a b->a b−>a,从点 b b b出发,可以到达点 a a a。
那么对于所有的边都像上述一样反向建边,然后从任意一点
i
i
i出发,那么它可以遍历到的所有点都是点
i
i
i的祖先(并且数据保证了不出现自环),然后将出现的点假如到vector
数组中,保证从小到大的顺序即可。
代码
class Solution {
public:
vector<int>e[1000+50];
int vis[1000+50];
void dfs(int x,int f){
vis[x]=1;
for(int i=0;i<e[x].size();i++){
if(!vis[e[x][i]]){
dfs(e[x][i],x);
}
}
}
vector<vector<int>> getAncestors(int n, vector<vector<int>>& edges) {
for(int i=0;i<edges.size();i++){
for(int j=0;j<edges[i].size();j++){
int x=edges[i][0],y=edges[i][1];
e[y].push_back(x);
}
}
vector<vector<int> >ans;
for(int i=0;i<n;i++){
memset(vis,0,sizeof(vis));
dfs(i,i);
vector<int>a;
for(int j=0;j<n;j++){
if(i==j||!vis[j])continue;
a.push_back(j);
}
ans.push_back(a);
}
return ans;
}
};
题目
5237.得到回文串的最少操作次数
题目大意
给你一个只包含小写英文字母的字符串 s
。
每一次 操作 ,你可以选择 s
中两个 相邻 的字符,并将它们交换。
请你返回将 s
变成回文串的 最少操作次数 。
注意 ,输入数据会确保 s
一定能变成一个回文串。
样例
数据规模
思路
对于字符串能否变成回文串 ,判断两种情况
- 从右边找不到对应的字符:
- 字符串长度为偶数,不能有数量为 1 1 1的字符
- 字符串长度为奇数,只能有一个数量为 1 1 1的字符
- 从右边能找到对应的字符:
- 这时候就把这个字符移动到左边字符对称的右边的位置,前边和后边的这两个字符分别向后和向前移动
问题就转变为了:每次完成字符串(......)
转化为x(......)x
,然后再转化为xy(......)yx
,直到变成对称的过程。
代码:
代码
class Solution {
public:
int minMovesToMakePalindrome(string s) {
int n=s.length();
int k=n-1,flag,ans;
ans=flag=0;
for(int i=0;i<k;i++){
for(int j=k;j>=i;j--){
if(j==i){
flag=1;
ans=ans+n/2-i;
}
else if(s[i]==s[j]){
for(int o=j;o<k;o++){
swap(s[o],s[o+1]);
ans++;
}
k--;
break;
}
}
}
return ans;
}
};