数据结构基础

1、两个queue实现stack

解题思路

首先我们需要理一下队列和栈,队列特点是先进先出,栈的特点是先进后出,对应的基本操作:
  • 队列的操作有:push 入队,front 取队首元素,pop 队首元素出队,empty 判断是否为空
  • 栈的操作有:push 入栈,top 取栈顶元素,pop 栈顶元素出栈,empty 判断是否为空
用两个队列实现栈,最简单的思路是用第一个队列模拟栈,那么第一个队列的元素顺序应该和插入顺序是相反的。如果我们在每次插入元素时,将其放到第一个队列的队首,同时队列中原来的元素顺序保持不变(和插入顺序相反),那么就可以保证这个队列的出队顺序和栈的出栈顺序相同。
我们可以通过第二个队列来辅助实现,具体地,在插入一个元素时,先将其放到第二个队列(第二个队列在插入时为空,所以新元素在第二个队列的队首),接着将第一个队列里的元素依次放到第二个队列。那么此时第二个队列就满足新元素在队首,其它元素顺序保持不变。交换两个队列,就保证了第一个队列出队顺序和栈的出栈顺序相同,插入完第二个队列仍保持空。这样pop操作就可以直接用第一个队列的pop操作实现。

C++代码实现如下
class MyStack {
public:
 queue<int> queue_0;
 queue<int> queue_1;

 MyStack() {}

 void push(int value) {
 queue_1.push(value); // 插入到第二个队列
 while (!queue_0.empty()) { // 把第一个队列的元素全放到第二个队列
 queue_1.push(queue_0.front());
 queue_0.pop();
 }
 swap(queue_0, queue_1); // 交换
 }

 void pop() {
 queue_0.pop(); // 栈的出栈顺序和第一个队列的出队顺序相同
 }

 int top() {
 int value = queue_0.front(); // 第一个队列的队首就是栈顶
 return value;
 }

 bool empty() {
 return queue_0.empty(); // 栈的元素全放在第一个队列
 }
 
 int size() {
 return queue_0.size(); 
 }
};
队列的push、pop、front操作时间复杂度为O(1),那么实现的栈的push操作复杂度为O(n),pop和top操作时间复杂度为O(1)

扩展

用一个队列实现栈
此时队列中元素不借助额外数据结构是不能逆置的, 但我们可以通过队列的size来知道栈顶在队列的第几个元素,然后我们就可以通过出队入队操作将栈顶元素移到队首。具体代码实现如下:
class MyStack {
public:
 queue<int> queue_0;
 queue<int> queue_1;

 MyStack() {}

 void push(int value) {
 queue_1.push(value);
 while (!queue_0.empty()) {
 queue_1.push(queue_0.front());
 queue_0.pop();
 }
 swap(queue_0, queue_1);
 }

 void pop() {
 queue_0.pop();
 }

 int top() {
 int value = queue_0.front();
 return value;
 }

 bool empty() {
 return queue_0.empty();
 }
};


class MyStack {
 queue<int> q;
public:
 MyStack() {
 while (!q.empty()) q.pop();
 }
 
 void push(int x) {
 q.push(x);
 }
 
 void pop() {
 int sz = q.size() - 1;
 while (sz--) {
 int tmp = q.front();
 q.pop();
 q.push(tmp);
 }
 q.pop();
 }
 
 int top() {
 int sz = q.size();
 int tmp;
 while (sz--) {
 tmp = q.front();
 q.pop();
 q.push(tmp);
 }
 return tmp;
 }
 
 bool empty() {
 return q.empty();
 }
};
此时插入复杂度O(1),pop和top操作O(n)
另一个扩展:用两个栈实现队列

2、用随机产生7以内数字的函数去写随机产生10以内数字的函数

解答思路:只要产生了目标范围内的随机数,则直接返回,如果产生的随机数不在目标范围内,则丢弃该值,重新取样。由于目标范围内的数字被选中的概率相等,则获得了一个均匀分布。
假定rand7( )来获得rand10(),显然rand7需要至少执行2次,否则产生不了1-10的数字。通过执行rand7两次,可以获得1-49的整数。又因为49不是10的倍数,所以需要丢弃一些值。代码如下:
nt rand10() { 
 int row, col, idx; 
 do { 
 row = rand7(); 
 col = rand7(); 
 idx = col + (row-1)*7; 
 } while (idx > 40); 
 return 1 + (idx-1)%10; 
} 
由于row范围为1-7,col范围为1-7,则idx值范围是1-49,大于40的值被丢弃,这样剩下1-40范围内的数字,通过取模,最后返回10以内范围结果。

优化:
对于大于40的数,不一定马上丢弃,可以对41-49的数减去40可得到1-9的随机数,而rand7可以产生1-7的随机数,这样可以生成1-63的随机数,对于1-60可以直接返回,而61-63丢弃,则需要丢弃的数只有3个,相比之前的9个效率有所提升。而对于61-63的数,减去60后为1-3,rand产生1-7,这样可以再利用产生1-21的数,对于1-20直接返回,对于21直接丢弃,这样丢弃的数只剩一个,又可优化效率。代码如下:
int rand10Imp() {
 int a, b, idx;
 while (true) {
 a = rand7();
 b = rand7();
 idx = b + (a-1)*7;
 if (idx <= 40)
 return 1 + (idx-1)%10;
 a = idx-40;
 b = rand7();
 // 得到分布 1 - 63
 idx = b + (a-1)*7;
 if (idx <= 60)
 return 1 + (idx-1)%10;
 a = idx-60;
 b = rand7();
 // 得到分布 1-21
 idx = b + (a-1)*7;
 if (idx <= 20)
 return 1 + (idx-1)%10;
 }
}


全部评论

相关推荐

头顶尖尖的程序员:我是26届的不太懂,25届不应该是找的正式工作吗?为什么还在找实习?大四还实习的话是为了能转正的的岗位吗
点赞 评论 收藏
分享
06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务