1 . 用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:用stack2用于输出,每次存入stack1,当要输入时,倒入到stack2。
代码:
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
if(stack2.empty())
{
while(!stack1.empty())
{
stack2.push(stack1.top());
stack1.pop();//明确出栈和取栈顶元素的区别
}
}
int p = stack2.top();//可能需要抛出一个异常,如果stack2还为空的话
stack2.pop();
return p;
}
private:
stack<int> stack1;
stack<int> stack2;
};
2. 包含mini函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
思路:
考虑使用两个栈,一个数据栈,等同于普通的栈,实现push pop peek 等操作;另一个辅助栈实现min函数。
当两个栈为空时,push进去的第一个值即为最小值;
push第二个元素时,若push的值<辅助栈顶元素(此处即第一个值),则将此值压进辅助栈;若push的值大于等于辅助栈顶元素,则将辅助栈顶元素再次push进去。
pop的时候,数据栈辅助栈均弹出顶元素。
代码:
class Solution {
public:
stack<int> s1,s2;
void push(int value) {
s1.push(value);
if(s2.empty()) s2.push(value);
else
{
int t = s2.top();
s2.push(value > t ? t:value);
}
}
void pop() {
if(!s1.empty()) s1.pop();
if(!s2.empty()) s2.pop();
}
int top() {
if(!s1.empty()) return s1.top();
return -1;
}
int min() {
if(!s2.empty()) return s2.top();
return -1;
}
};
3. 栈的压入和弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路:
借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
….
依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
代码:
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
if(pushV.size() == 0 || popV.size() == 0)
return false;
stack<int> s;
int index = 0;
for(int i = 0; i < pushV.size(); i ++)
{
s.push(pushV[i]);
while(!s.empty() && s.top() == popV[index])
{
s.pop();
index ++;
}
}
return s.empty();
}
};
4. 括号序列
给出一个仅包含字符’(’,’)’,’{’,’}’,’[‘和’]’,的字符串,判断给出的字符串是否是合法的括号序列
括号必须以正确的顺序关闭,"()“和”()[]{}“都是合法的括号序列,但”(]“和”([)]"不合法。
代码:
class Solution {
public:
/**
*
* @param s string字符串
* @return bool布尔型
*/
bool isValid(string s) {
// write code here
stack<char> stk;
for(int i = 0; i < s.length(); i ++)
{
if(s[i] == '(' || s[i] == '{' || s[i] == '[')
stk.push(s[i]);
if(s[i] == ')')
{
if(!stk.empty() && stk.top() == '(')
{
stk.pop();
continue;
}
else
return false;
}
if(s[i] == '}')
{
if(!stk.empty() && stk.top() == '{')
{
stk.pop();
continue;
}
else
return false;
}
if(s[i] == ']')
{
if(!stk.empty() && stk.top() == '[')
{
stk.pop();
continue;
}
else
return false;
}
}
return stk.empty();
}
};
5. 数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:
我们注意到当数据保存到容器中时,可以分为两部分,左边一部分的数据要比右边一部分的数据小。如下图所示,P1是左边最大的数,P2是右边最小的数,即使左右两部分数据不是有序的,我们也有一个结论就是:左边最大的数小于右边最小的数。
因此,我们可以有如下的思路:用一个最大堆实现左边的数据存储,用一个最小堆实现右边的数据存储,向堆中插入一个数据的时间是O(logn),而中位数就是堆顶的数据,只需要O(1)的时间就可得到。
而在具体实现上,首先要保证数据平均分配到两个堆中,两个堆中的数据数目之差不超过1,为了实现平均分配,可以在数据的总数目是偶数时,将数据插入最小堆,否则插入最大堆。
代码:
class Solution {
public:
priority_queue<int, vector<int>, less<int>> left;
priority_queue<int, vector<int>,greater<int>> right;
void Insert(int num)
{
if(left.empty() || left.top() > num)
left.push(num);
else
right.push(num);
if(right.size()+2 == left.size())
{
right.push(left.top());
left.pop();
}
if(left.size()+1 == right.size())
{
left.push(right.top());
right.pop();
}
}
double GetMedian()
{
return (right.size() == left.size())? (right.top()+left.top())/2.0: left.top();
}
};