#pre
面试的时候遇到的,面试官要求手写代码。问题本身不难,但是需要注意自己的想法是否最优
#问题分析
堆是后进先出,栈是先进先出,所以自然而然有了想法1,用栈去存储数据,如果需要返回数据,那么新建一个栈,把原来栈所有的东西弹出来,退出最底部的元素,返回给外部,然后将栈还原。
//使用语言java
import java.util.*;
//这里假定访问方式是单线程,如果多线程访问 需要对stack进行保护
public class Solution{
Stack<Object> valueStack;
public Solution(){
//这部分声明不确定,java中可能是这么调用的
valueStack = new ArrayList<>();
}
//返回值表明压栈是否成功
public boolean push(Object value){
//栈溢出的时候会返回异常
try{
valueStack.push(value);
}catch(Exception e){
return false;
}
return true;
}
//假定存储的元素不会是null
public Object pop(){
if(valueStack.size() <= 0){
return null;
}
Stack cacheStack = new ArrayList<>();
while(valueStack.size() > 0){
cacheStack.push(valueStack.pop());
}
Object reval = cacheStack.pop();
while(cacheStack.size() > 0){
valueStack.push(cacheStack.pop());
}
return reval;
}
}
#提示1:栈为什么还原
在想法1的基础上,在我们每次弹出一个元素的时候我们需要将栈反转一次,然后还原回来,如果连续遇到两次弹出操作,这个还原操作反而是浪费时间的操作,所以这里可以得到想法2,我们可以通过状态量来检测这个连续弹出的情况,如果不是连续弹出,然后就可以不用还原栈。
//使用语言java
import java.util.*;
//这里假定访问方式是单线程,如果多线程访问 需要对stack进行保护
public class Solution{
Stack<Object> valueStack;
Stack<Object> cacheStack;
boolean inOrigin;
public Solution(){
//这部分声明不确定,java中可能是这么调用的
valueStack = new ArrayList<>();
cacheStack = new ArrayList<>();
inOrigin = true;
}
//返回值表明压栈是否成功
public boolean push(Object value){
if(value == null){
return false;
}
//栈溢出的时候会返回异常
try{
if(!inOrigin){
while(cacheStack.size() > 0){
valueStack.push(cacheStack.pop());
}
inOrigin = true;
}
valueStack.push(value);
}catch(Exception e){
return false;
}
return true;
}
//假定存储的元素不会是null
public Object pop(){
if(inOrigin){
while(valueStack.size() > 0){
cacheStack.push(valueStack.pop());
}
inOrigin = false;
}
if(cacheStack.size() <= 0){
return null;
}
Object reval = cacheStack.pop();
return reval;
}
}
#提示2:栈有没有必要还原
重新思考数据的表示,这里假设存在两个栈(baseStack和reverseStack),数据存储在baseStack中,在时间点A,如果需要弹出元素,那么reverseStack会按照逆序存储这个时间点A时baseStack中所剩下的元素,之后添加的所有元素都是在reverseStack中元素之后的,在reverseStack元素没有弹完之前,后续添加的元素不需要压入到reverseStack,也就是后续添加的元素可以直接堆积在baseStack中,而我们之前还原栈的操作,只是保证在弹出栈的时候,reverseStack中按照顺序存储了所有数据。由此我们得到了想法3,我们声明两个栈(baseStack和reverseStack),在弹出时,如果reverseStack没有元素,那么就将baseStack的元素以此放入到reverseStack中,然后弹出尾部,在压入时,数据直接压入到baseStack中。
//使用语言java
import java.util.*;
//这里假定访问方式是单线程,如果多线程访问 需要对stack进行保护
public class Solution{
Stack<Object> valueStack;
Stack<Object> cacheStack;
public Solution(){
//这部分声明不确定,java中可能是这么调用的
valueStack = new ArrayList<>();
cacheStack = new ArrayList<>();
}
//返回值表明压栈是否成功
public boolean push(Object value){
if(value == null){
return false;
}
//栈溢出的时候会返回异常
try{
valueStack.push(value);
}catch(Exception e){
return false;
}
return true;
}
//假定存储的元素不会是null
public Object pop(){
if(cacheStack.size() <= 0){
while(valueStack.size() > 0){
cacheStack.push(valueStack.pop());
}
if(cacheStack.size() <= 0){
return null;
}
}
Object reval = cacheStack.pop();
return reval;
}
}
#总结
在操作数据的时候需要进行仔细分析,尽可能避免无意义的操作。