数据结构与算法训练:第十七弹

1. 知识点总结

1h32min实现AC成就

本次主要涉及到的知识点是字符串处理、简单贪心、并查集以及二叉搜索树的构建。

题目难度知识点
1112 Stucked Keyboard🎯字符串处理
1113 Integer Set Partition🎯简单贪心
1114 Family Property🎯🎯并查集
1115 Counting Nodes in a Binary Search Tree🎯🎯二叉搜索树BST

2. 分题题解

2.1 1112 Stucked Keyboard

不是很难但是思路不好的话解决起来会很麻烦。

主要思路:

  • 因为出现的字符是{a-z}, {0-9} and _,于是在此先用函数getId将字符和对应id作简单映射
  • 假设所有键都是坏的,只要某个键连续出现的次数不能被k整除,则此键正常,用isOk标记
  • 输出结果的时候,对于坏键,每次跳跃k,好键每次跳跃1
#include<bits/stdc++.h>
using namespace std;
string str;
string word;
string sentence;
bool isOk[40]={false};//保存是否是好的 
bool isChecked[40]={false};//保存已经输出的"坏键" 
int id,k;
int getId(char a){
	if(a<='z'&&a>='a'){
		return a-'a';//0-25
	}else if(a<='9'&&a>='0'){
		return a-'0'+26;//26-35
	}else{
		return 36;
	}
}
int main(){
	scanf("%d",&k);
	getchar();
	getline(cin,str);
	//检测某个字符是否每次出现都是k
	int len=str.length(); 
	int cnt=1;
	str+=".";
	for(int i=1;i<len+1;i++){
		//更新计算连续字符 
		if(str[i]==str[i-1]){
			cnt++;
		}else{
			if(cnt%k!=0){
				id=getId(str[i-1]);
				isOk[id]=true;
			}
			cnt=1;
		}
	}
	//统计出事的 
	for(int i=0;i<len;){
		id=getId(str[i]);
		sentence+=str[i];
		if(!isOk[id]){
			if(!isChecked[id]){
				printf("%c",str[i]);
				isChecked[id]=true;
			}
			i+=k;
			continue;
		}else{
			i++;
		}
	} 
	printf("\n%s",sentence.c_str());
	return 0;
} 

2.2 1113 Integer Set Partition

看完题目大概就可以得出简单从小到大排序,前N/2给Set2,其他给Set1可以使得Set1的和大于Set2最大化

#include<bits/stdc++.h>
using namespace std;
//最小化n1-n2 最大化S1-S2
int N,n1,n2,sum1=0,sum2=0;
vector<int>v; 
int main(){
	scanf("%d",&N);
	v.resize(N);
	for(int i=0;i<N;i++){
		scanf("%d",&v[i]);
	}
	sort(v.begin(),v.end());
	n2=N>>1;
	n1=N-n2;
	for(int i=0;i<n2;i++){
		sum2+=v[i];
	}
	for(int i=n2;i<N;i++){
		sum1+=v[i];
	}
	printf("%d %d",n1-n2,sum1-sum2);
	return 0;
}

2.3 1114 Family Property

并查集模板,主要是需要另外开AE数组去存每个家族的财产信息以及最后输出的时候需要新建结构体排序。

#include<bits/stdc++.h>
using namespace std;
int N,id,fid,mid,k,e,a;
vector<int>cids;
int f[10000];
int root[10000]={0};
int E[10000]={0};
int A[10000]={0};
bool exist[10000]={false};
const int maxn=9999;
struct Node{
	int id;
	int sum;
	double avg_e,avg_a;
};
vector<Node>ans;
bool cmp(Node a,Node b){
	if(a.avg_a!=b.avg_a){
		return a.avg_a>b.avg_a;
	}else{
		return a.id<b.id;
	}
}
int Find(int a){
	int x=a;
	while(a!=f[a]){
		a=f[a];
	}
	while(x!=f[x]){
		int temp=x;
		x=f[x];
		f[temp]=a;
	}
	return a;
}
void Union(int a,int b){
	int fa=Find(a);
	int fb=Find(b);
	if(fa<fb){
		f[fb]=fa;
		root[fa]+=root[fb];
		root[fb]=0;
	}else if(fb<fa){
		f[fa]=fb;
		root[fb]+=root[fa];
		root[fa]=0;
	}
}
int main(){
	scanf("%d",&N);
	for(int i=0;i<=maxn;i++){
		f[i]=i;
		root[i]=1;
	}
	while(N--){
		scanf("%d%d%d%d",&id,&fid,&mid,&k);
		cids.resize(k);
		for(int i=0;i<k;i++){
			scanf("%d",&cids[i]);
		}
		scanf("%d%d",&e,&a);
		//注册用户信息
		exist[id]=true;
		E[id]+=e; 
		A[id]+=a;
		//将信息融合
		if(mid!=-1){
			Union(id,mid);
			exist[mid]=true;
		} 
		if(fid!=-1){
			Union(id,fid);
			exist[fid]=true;
		}
		for(int i=0;i<k;i++){
			Union(id,cids[i]);
			exist[cids[i]]=true;
		}
	}
	for(int i=0;i<=maxn;i++){
		if(exist[i]){
			int r=Find(i);
			if(i!=r){
				E[r]+=E[i];
				A[r]+=A[i];
			}
		}
	}
	Node temp;
	for(int i=0;i<=maxn;i++){
		if(exist[i]&&root[i]!=0){
			temp.id=i;
			temp.sum=root[i];
			temp.avg_e=E[i]*1.0/root[i];
			temp.avg_a=A[i]*1.0/root[i];
			ans.push_back(temp);
		}
	}
	sort(ans.begin(),ans.end(),cmp);
	int len=ans.size();
	printf("%d",len);
	for(int i=0;i<len;i++){
		printf("\n%04d %d %.3f %.3f",ans[i].id,ans[i].sum,ans[i].avg_e,ans[i].avg_a);
	}
	return 0;
}

2.4 1115 Counting Nodes in a Binary Search Tree

思路:

  • 构建二叉搜索树:注意关于左孩子可以和根节点值一样
  • 层次遍历存储每一层的节点值
  • 最后输出倒数两层节点数大小
#include<bits/stdc++.h>
using namespace std;
int N,temp;
struct Node{
	int val;
	Node*left=NULL;
	Node*right=NULL;
	int level;
};
void Insert(Node* &root,int val){
	if(root==NULL){
		root=new Node;
		root->val=val;
	}else{
		if(val<=root->val){
			Insert(root->left,val);
		}else if(val>root->val){
			Insert(root->right,val);
		}
	}
	return;
}
int max_level=0;
vector<vector<int> >nodes;
void levelTravel(Node*root){
	queue<Node*>q;
	root->level=0;
	q.push(root);
	while(!q.empty()){
		Node*top=q.front();
		if(top->level>max_level){
			max_level=top->level;
		}
		if(top->left!=NULL){
			top->left->level=top->level+1;
			q.push(top->left);
		}
		if(top->right!=NULL){
			top->right->level=top->level+1;
			q.push(top->right);
		}
		//printf("level:%d val:%d\n",top->level,top->val);
		nodes[top->level].push_back(top->val); 
		q.pop();
	}
}
int main(){
	scanf("%d",&N);
	Node*root=NULL;
	nodes.resize(N);
	for(int i=0;i<N;i++){
		scanf("%d",&temp);
		Insert(root,temp);
	}
	levelTravel(root);
	int n1=nodes[max_level].size();
	int n2=nodes[max_level-1].size();
	printf("%d + %d = %d",n1,n2,n1+n2);
	return 0;
}

3. 参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值