洛谷P1160题解

题意

一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:

  1. 先将1号同学安排进队列,这时队列中只有他一个人;

  2. 2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;

  3. 从队列中去掉编号为M(M<N)个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号

输出 输出最后队列从左至右所有同学的编号

思路 这道题需要较快的删除、插入。

大部分小伙伴可能跟我的想法一样,第一时间想到的便是链表,所以我们就开始按照之前的知识,通过指针这一结构性开销,设计我们的链表,然后测试案例也能过,结果交上去😢

没错,超时了 ,这时可能大家才注意到,这个题的核心除了能较快的插入和删除意外,还需要较快的查询。

我相信之前看过我博客的小伙伴们,是知道我最近在打紫书,那么了解紫书的小伙伴们,应该知道紫书还介绍了一种设计链表的方法——用数组模拟

用数组模拟,(以双向链表为例),用两个数组next,pre分别代替原来的*next 和 *pre,其实与使用指针的模拟差不多,只不过把指针换作了数组,但是用数组模拟,在这种情况下,查找效率更高

知道思路了,让我们回顾一下链表的插入和删除

链表的插入和删除 (这里是使用数组模拟的,记得回想用指针模拟时的操作)

插入

 假如 i 是需要插入位置的上一个位置  k为需要插入的元素

指针:                                                            数组        

k->next=i->next;                                           next[k]=next[i];

i->next->pre=k;                                             pre[next[i]]=k;

i->next=k;                                                      next[i]=k;

k-->pre=i;                                                       pre[k]=i;

删除 

 假如i 是需要删除位置

指针:                                                            数组:

i->pre->next=i->next;                                   next[pre[i]]=next[i];

i->next->pre=i->pre;                                     pre[next[i]]=pre[i];

代码实现:

 


#include<iostream>
#include<cstring> 
using namespace std;
const int N=1e5+5;//
int Next[N],pre[N],nums[N];//开辟数组,nums是判断这个数还在不在链表里
void print();
int main()
{
	int n;
	scanf("%d",&n);
	memset(nums,0,sizeof(nums));
	Next[0]=1;//做个标志,没有任意个数的next为1,因为数是从1开始的 
	pre[0]=n;//做个标记,没有任意个数的pre为n,因为数是从n结束的
	Next[1]=0;
	pre[1]=0;
	int k,p;
	for(int i=2;i<=n;i++)
	{
		scanf("%d%d",&k,&p);
        //插入操作
		if(p==0)
		{
			Next[i]=k;
			pre[i]=pre[k]; 
			Next[pre[i]]=i;
			pre[k]=i;
		} 
		else 
		{
			Next[i]=Next[k];
			pre[Next[k]]=i;
			Next[k]=i;
			pre[i]=k;
		}
	} 
	int M,x;
	scanf("%d",&M);
//删除操作
	while(M--)
	{
		scanf("%d",&x);
		if(nums[x]==0)
		{
			Next[pre[x]]=Next[x];
			pre[Next[x]]=pre[x];
			nums[x]=1;
		}
	}
    //打印答案
	print();
} 
void print()
{
	int i=Next[0];
	while(i!=0)//如果i的下标为0,则就不输出了
	{
		printf("%d ",i);
		i=Next[i];
	}
	printf("\n");
}

个人总结

做一件事最需要的就是持之以恒的精神,虽然目前为止我只写了五篇题解,但是我会继续坚持下去的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值