总结:……从后往前刷题是正确的,前面感觉比后面的难一点,套路题少了很多
题目 | 难度 | 知识点 |
---|---|---|
1043 Is It a Binary Search Tree | 🎯🎯 | BST和镜像BST |
1044 Shopping in Mars | 🎯 | 暴力 |
1045 Favorite Color Stripe | ✨✨ | 动态规划21/30 |
这题的主要难点在于对于镜像的BST树,不仅是构建的时候排序需要按照降序排列in
数组,还需要修改build
函数中k
的选取过程,如下面AC代码所示,镜像树在构建的时候,k
是从大往小遍历的,这会导致在相等值切分的时候会出现左右子树分配问题,最终影响一个测试点被卡。
#include
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;
}
这题暴力破解即可~每次ans_a
和ans_b
中存储当前的最优解的集合,当遇到更优解时清空上两个数组,同时更新min_def
,加入新的a
和b
#include
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;
}
一开始用的时DFS,拿了19分,超时2个测试点,报错1个测试点
后来想到的是找到最长公共子序列即可:于是想到DP中的LCS问题
得分21/30,DP代码如下:
#include
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
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;
}