1定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的分函数(时间复杂度应为O(1))。
答:这个问题首先需要建立两个栈,一个数据栈,另一个栈用来存储最小值.stackMin,stackData。
①第一种方法
入栈:当stackMin栈为空或者值<stackMin.top()时,值入stackMin栈如果值大于stackMin的栈顶,则将stackMin的栈顶重复入栈最后值入栈stackData。
class Solution {
public:
void push(int value) {
if(stackMin.empty()||value<stackMin.top())
stackMin.push(value);
else{
int top_val=stackMin.top();
stackMin.push(top_val);
}
stackData.push(value);
}
void pop() {
if(stackData.empty())
throw exception();
stackData.pop();
stackMin.pop();
}
int top() {
return stackData.top();
}
int min() {
return stackMin.top();
}
private:
stack<int> stackData,stackMin;
};
第二种方法②:入栈如果stackMin为空或者值小于等于stackMin栈顶的话。价值入栈stackMin否则只入栈stackData。
出栈时,我们需要判断stackData的栈顶是否等于stackMin的栈顶。如果是的话两个栈都出栈。否则就只stackData出栈。
class Solution {
public:
void push(int value) {
if(stackMin.empty()||value<=stackMin.top())
stackMin.push(value);
stackData.push(value);
}
void pop() {
if(stackData.empty())
throw exception();
if(stackData.top()==stackMin.top())
stackMin.pop();
stackData.pop();
}
int top() {
return stackData.top();
}
int min() {
return stackMin.top();
}
private:
stack<int> stackData,stackMin;
};
2.编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(压入,弹出)。
给定一个操作序列ope及它的长度n,其中元素为正数代表push操作,为0代表pop操作,保证操作序列合法且一定含pop操作,请返回pop的结果序列。
测试样例:
[1,2,3,0,4,0],6
返回:[1,2]
答:使用两个栈实现一个队列需要一个推栈一个弹出栈,推栈主要用于数据入栈时存储,流行栈是为了维护正确的顺序,因为入栈时是后进先出的,但是队列是先进先出,所以我们先将数据入第一个栈,当需要使用到队列的出队操作时,我们就将第一个栈的数据全部丢到第二个栈中,注意此时由于是以原来入栈顺序相反的顺序入另一个栈的,所以另一个栈出栈时就有了队列的先进先出的特性。需要注意的是将第一个栈的数据挪向第二个栈时是只有当第二个栈为空时才操作。当第二个栈还有数据时直接出栈就行了。
class queue_1{
public: void push(int val)
{
sta_1.push(val);
}
int pop()
{
if(sta_1.empty()&&sta_2.empty())
throw exception();
if(sta_2.empty())
{
while(!(sta_1.empty()))
{
int val=sta_1.top();
sta_1.pop();
sta_2.push(val);
}
}
int temp=sta_2.top();
sta_2.pop();
return temp;
}
private: stack<int> sta_1,sta_2;
};
class TwoStack {
public:
vector<int> twoStack(vector<int> ope, int n) {
// write code here
if(ope.empty()||n<=0)
return vector<int>();
int nums=0;
vector<int> vec;
queue_1* q=new queue_1();
for(int i=0;i<n;i++)
if(ope[i]>0)
q->push(ope[i]);
else if(ope[i]==0)
vec.push_back(q->pop());
return vec;
}
};
3.实现一个栈的逆序,但是只能用递归函数和这个栈本身的弹出操作来实现,而不能自己申请另外的数据结构。
给定一个整数数组A即为给定的栈,同时给定它的大小n,请返回逆序后的栈。
测试样例:
[4,3,2,1],4
返回:[1,2,3,4]
int find_stackDi(stack<int>& sta)
{
if (sta.size() == 1)
{
int val = sta.top();
sta.pop();
return val;
}
int val = sta.top();
int result;
sta.pop();
result=find_stackDi(sta);
sta.push(val);
return result;
}
void reverseStack(stack<int>& sta)
{
if (sta.empty())
return ;
int val = find_stackDi(sta);
reverseStack(sta);
sta.push(val);
}
4.请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中。
给定一个int [] 数字(C ++中为vector&ltint>),其中第一个元素为栈顶,请返回排序后的栈。请注意这是一个栈,意味着排序过程中你只能访问到第一个元素。
测试样例:
[1,2,3,4,5]
返回:[5,4,3,2,1]
答:需要一个辅助栈help,当数据栈出栈时把值赋给cur,如果help栈为空则直接插入help栈。如果不为空同时cur的值比help的栈顶值小,则说明此时cur代替help的栈顶 依然可以满足栈顶方向的值小于栈底方向的值。如果cur的值大于help栈的栈顶值,则说明此时cur如果放到help栈顶的话会破坏(栈顶方向的值小于栈底方向值的特性)。所以我们此时将help栈顶不断出栈,同时栈顶元素也在不断更新,直到遇到cur小于help栈顶值时,cur就可以放入。然后不断重复这个操作,直到数据栈的数据都放到了help栈,最终help栈的数据将是从栈顶到栈底 是从小到大的。如果需要需要得到从大到小的话,将元素值不断出栈到原数据栈就行了。(原理有点像 插入排序 找最终应该插入的位置 特别是内部循环的代码)
class TwoStacks {
public:
vector<int> twoStacksSort(vector<int> numbers) {
// write code here
if(numbers.empty())
return vector<int>();
vector<int> temp;
while(!numbers.empty())
{
int val=numbers.back();
numbers.pop_back();
while(!temp.empty()&&val>temp.back())
{
numbers.push_back(temp.back());
temp.pop_back();
}
temp.push_back(val);
}
return temp;
}
};
5.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5-是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列(注意:这两个序列的长度是相等的)。
答:需要用到一个辅助栈 去模拟如果按输出序列 输入序列 辅助栈最终是否能模拟完毕 也就是为空。每一次辅助栈的栈顶应该与待输出数相同,如果相同则辅助栈出栈,然后遍历下一个待输出数。如果不相同的话则要按输入序列继续入栈。如果一直入栈到输入序列结束 还没有发现与辅助栈栈顶相同 则输出失败。
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.empty()||popV.empty())
return false;
int push_i,pop_j,push_next,pop_next;
push_i=pop_j=push_next=pop_next=0;
int length=pushV.size();
stack<int> temp;
while(pop_next-pop_j<length)
{
while(temp.empty()||temp.top()!=popV[pop_next])
{
if(push_next-push_i==length)
break;
temp.push(pushV[push_next]);
push_next++;
}
if(temp.top()!=popV[pop_next])
break;
temp.pop();
pop_next++;
}
if(temp.empty()&&pop_next-pop_j==length)
return true;
return false;
}
};
6.栈的应用:
① 浏览器的前进后退
答:可以使用两个栈来实现浏览器的前进后退功能。点击一个页面,入第一个栈,再点击继续入栈。如果要后退的话,就出栈并且 第二个栈入栈。这样第一个栈的栈顶就是上一个页面了。前进的话,就将第二个栈出栈返回到第一个栈中。如果点击了一个新的页面的话,就将第二个栈清空。
② 括号匹配
③ 调用函数时,使用栈来保存形参、局部变量、返回地址
④ 中序表达式、前序表达式、后序表达式
中缀转前缀
与中缀转后缀相似,不同点在于因为要从右到左扫描,先遇到的是右括号。而且最后拼接的结果与预期结果正好相反,因此需要另一个栈result存放中间结果,还有一个不同点在于比较运算符的优先级时,相同优先级也要进栈,步骤如下:
(1)创建一个栈存放运算符,创建一个result栈存放中间结果
(2)从右到左扫描中缀表达式
(3)如果是操作数,压入result栈
(3.1)如果是右括号或栈为空,直接进运算符栈
(3.2)如果是左括号,栈顶元素出栈,压入result栈,直到右括号出栈,但右括号不输出
(3.3)如果是其他运算符,比较与栈顶运算符的优先级,如果大于或等于,进栈,如果小于,栈顶元素出栈并压入result栈,然后该运算符压入运算符栈
(4)扫描完成后,将运算符栈中的剩余元素压入result栈
下面以5*(2+3)-4为例:
此段转载自:
---------------------
作者:StriverLi
来源:CSDN
原文:https://blog.csdn.net/StriverLi/article/details/68936153
中缀转后缀
步骤:
(1)创建一个栈存放运算符,用String类对象postfix将结果拼接起来。
(2)从左到右扫描中缀表达式
(3)如果是操作数,拼接到postfix
(3.1)如果是左括号或栈为空,直接进栈
(3.2)如果是右括号,栈顶元素出栈,拼接到postfix,直到左括号出栈,但左括号不输出
(3.3)如果是其他运算符,比较与栈顶运算符的优先级,如果大于,进栈,如果小于或等于,栈顶元素出栈并拼接到postfix,将该运算符进栈
(4)扫描完成后,将栈中是运算符全部拼接的str
下面以5*(2+3)-4为例:
---------------------
作者:StriverLi
来源:CSDN
原文:https://blog.csdn.net/StriverLi/article/details/68936153
版权声明:本文为博主原创文章,转载请附上博文链接!