数据结构与算法复习:第三十三弹

1. 知识点总结

总结:……从后往前刷题是正确的,前面感觉比后面的难一点,套路题少了很多

题目难度知识点
1043 Is It a Binary Search Tree🎯🎯BST和镜像BST
1044 Shopping in Mars🎯暴力
1045 Favorite Color Stripe✨✨动态规划21/30

2. 分题题解

2.1 1043 Is It a Binary Search Tree

这题的主要难点在于对于镜像的BST树,不仅是构建的时候排序需要按照降序排列in数组,还需要修改build函数中k的选取过程,如下面AC代码所示,镜像树在构建的时候,k是从大往小遍历的,这会导致在相等值切分的时候会出现左右子树分配问题,最终影响一个测试点被卡。

#include<bits/stdc++.h>
using namespace std;
vector<int>pre,in;
int N;
struct Node{
	int val;
	Node*left=NULL;
	Node*right=NULL;
};
Node*root=NULL;
bool canBuild=true;
Node*build(int inL,int inR,int preL,int preR){
	if(inL<0||preL<0||inR>=N||preR>=N||inL>inR||preL>preR){
		return NULL;
	}
	Node*node=new Node;
	node->val=pre[preL];
	int k;
	bool flag=false;
	for(k=inL;k<=inR;k++){
		if(in[k]==node->val){
			flag=true;
			break;
		}
	}
	if(!flag){
		canBuild=false;
		return NULL;
	}
	int num=k-inL;
	node->left=build(inL,k-1,preL+1,preL+num);
	node->right=build(k+1,inR,preL+num+1,preR);
	return node;
}
Node*build1(int inL,int inR,int preL,int preR){
	if(inL<0||preL<0||inR>=N||preR>=N||inL>inR||preL>preR){
		return NULL;
	}
	Node*node=new Node;
	node->val=pre[preL];
	int k;
	bool flag=false;
	for(k=inR;k>=inL;k--){
		if(in[k]==node->val){
			flag=true;
			break;
		}
	}
	if(!flag){
		canBuild=false;
		return NULL;
	}
	int num=k-inL;
	node->left=build(inL,k-1,preL+1,preL+num);
	node->right=build(k+1,inR,preL+num+1,preR);
	return node;
}
bool flag=false;
void postTravel(Node*root){
	if(root==NULL){
		return;
	}else{
		postTravel(root->left);
		postTravel(root->right);
		if(flag){
			printf(" ");
		}else{
			flag=true;
		}
		printf("%d",root->val);
	}
}
int main(){
	scanf("%d",&N);
	pre.resize(N);
	for(int i=0;i<N;i++){
		scanf("%d",&pre[i]);
	}
	in=pre;
	sort(in.begin(),in.end());
	root=build(0,N-1,0,N-1);
	if(!canBuild){
		sort(in.begin(),in.end(),greater<int>());
		canBuild=true;
		root=NULL;
		root=build1(0,N-1,0,N-1);
	}
	if(canBuild){
		printf("YES\n");
		postTravel(root);
	}else{
		printf("NO");
	}
	return 0;
} 

2.2 1044 Shopping in Mars

这题暴力破解即可~每次ans_aans_b中存储当前的最优解的集合,当遇到更优解时清空上两个数组,同时更新min_def,加入新的ab

#include<bits/stdc++.h>
using namespace std;
int N,M;
vector<int>v,pre_sum;
vector<int>ans_a,ans_b;
int min_def;
int main(){
	scanf("%d%d",&N,&M);
	v.resize(N+1);
	pre_sum.resize(N+1,0);
	for(int i=1;i<=N;i++){
		scanf("%d",&v[i]);
		pre_sum[i]=v[i]+pre_sum[i-1];
	}
	min_def=pre_sum[N]-M;
	for(int a=1;a<=N;a++){
		if(pre_sum[N]-pre_sum[a]+v[a]<M){
			break;
		}
		for(int b=a;b<=N;b++){
			int temp=pre_sum[b]-pre_sum[a]+v[a];
			if(temp<M){
				continue;
			}else{
				temp-=M;
			}
			if(temp>min_def){
				break;
			}else if(temp<min_def){
				min_def=temp;
				ans_a.clear();
				ans_b.clear();
				ans_a.push_back(a);
				ans_b.push_back(b);
			}else{
				ans_a.push_back(a);
				ans_b.push_back(b);
			}
		}
	}
	for(int i=0;i<ans_a.size();i++){
		printf("%d-%d\n",ans_a[i],ans_b[i]);
	}
	return 0;
}

2.3 1045 Favorite Color Stripe

一开始用的时DFS,拿了19分,超时2个测试点,报错1个测试点

后来想到的是找到最长公共子序列即可:于是想到DP中的LCS问题

得分21/30,DP代码如下:

#include<bits/stdc++.h>
using namespace std;
int N,M,L;
vector<int>f,v;
int max_len=0;
struct Node{
	int val;
	int cnt;
};
vector<Node>nodes(1);
int len;
int main(){
	scanf("%d%d",&N,&M);
	f.resize(M+1);
	for(int i=1;i<=M;i++){
		scanf("%d",&f[i]);
	}
	scanf("%d",&L);
	v.resize(L);
	int cnt;int temp;
	for(int i=0;i<L;i++){
		scanf("%d",&v[i]);
		if(i){
			if(v[i]==temp){
				cnt++;
			}else{
				Node node;
				node.val=temp;
				node.cnt=cnt;
				nodes.push_back(node);
				cnt=1;
				temp=v[i];
			}
		}else{
			temp=v[0];
			cnt=1;
		}
	}
	Node node;
	node.val=temp;
	node.cnt=cnt;
	nodes.push_back(node);
	len=nodes.size()-1;
	vector<vector<int> >dp(len+1,vector<int>(M+1,0));
	//dp[i][j] 
	for(int i=1;i<=len;i++){
		for(int j=1;j<=M;j++){
			if(nodes[i].val==f[j]){
				dp[i][j]=dp[i-1][j-1]+nodes[i].cnt;
			}else{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
	} 
	printf("%d",dp[len][M]);
	return 0;
}

看了柳神的代码理了一下思路:

  • 首先,按照喜欢的颜色序列,因为序列中元素不重复,所以是突破口,可以为每一个最喜欢的颜色用它们在序列中对应的下标替代
  • 同时,不需要所有最喜欢的颜色都出现
    于是原问题通过坐标替换可以变成一个经典的求最长不下降子序列的问题

AC代码如下

#include<bits/stdc++.h>
using namespace std;
int N,M,L,color,ans;
vector<int>favorite,colors,strip; 
int main(){
	scanf("%d%d",&N,&M);
	favorite.resize(M);
	colors.resize(N+1);
	for(int i=1;i<=M;i++){
		scanf("%d",&color);
		colors[color]=i;//喜欢颜色的序号 
	}
	scanf("%d",&L);
	for(int i=0;i<L;i++){
		scanf("%d",&color);
		if(colors[color]>=1){
			strip.push_back(colors[color]);
		}
	} 
	int len=strip.size();
	vector<int>dp(len,0);
	//需要计算最长不下降子序列的长度
	for(int i=0;i<len;i++){
		dp[i]=1;
		for(int j=0;j<i;j++){
			if(strip[i]>=strip[j]){
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		ans=max(ans,dp[i]);
	} 
	printf("%d",ans);
	return 0;
} 

3. 参考资料

1045. Favorite Color Stripe (30)-PAT甲级真题_柳婼的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值