三、队列&栈
JZ9 用两个栈实现队列
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
数据范围:n≤1000
要求:存储n个元素的空间复杂度为 O(n),插入与删除的时间复杂度都是 O(1)
push直接放入stack1,stack1用于存储数据。
pop 若stack2中有数据,直接pop,否则把stack1中的所有数据放入stack2,返回最上面的数。
class Solution
{
public:
void push(int node) {
stack1.push(node);
}
int pop() {
int result = 0;
if(stack2.empty()){
while(!stack1.empty()){
int tmp = stack1.top();
stack1.pop();
stack2.push(tmp);
}
}
result = stack2.top();
stack2.pop();
return result;
}
private:
stack<int> stack1;
stack<int> stack2;
};
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
self.stack1.append(node)
# write code here
def pop(self):
if len(self.stack2)==0:
while len(self.stack1):
tmp = self.stack1[len(self.stack1)-1]
self.stack1.remove(tmp)
self.stack2.append(tmp)
result = self.stack2[len(self.stack2)-1]
self.stack2.remove(result)
return result
JZ30 包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。
此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素
数据范围:操作数量满足0≤n≤300 ,输入的元素满足∣val∣≤10000
进阶:栈的各个操作的时间复杂度是 O(1) ,空间复杂度是 O(n)
借助辅助栈,他记录每进来node之后的最小值,pop的时候stack和辅助栈都需pop。
class Solution {
public:
stack<int> stack1, minstack;
void push(int value) {
stack1.push(value);
if(minstack.empty())
minstack.push(value);
else{
int tmp = minstack.top();
if(value<tmp)
minstack.push(value);
else
minstack.push(tmp);
}
}
void pop() {
stack1.pop();
minstack.pop();
}
int top() {
return stack1.top();
}
int min() {
return minstack.top();
}
};
class Solution:
def __init__(self):
self.minc = []
self.stack = []
def push(self, node):
self.stack.append(node)
if len(self.minc) == 0:
self.minc.append(node)
else:
tmp = self.minc[len(self.minc)-1]
if node < tmp:
self.minc.append(node)
else:
self.minc.append(tmp)
def pop(self):
result = self.stack[len(self.stack)-1]
self.stack.remove(result)
self.minc.remove(self.minc[len(self.minc)-1])
def top(self):
return self.stack[len(self.stack)-1]
def min(self):
return self.minc[len(self.minc)-1]
JZ31 栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
- 0<=pushV.length == popV.length <=1000
- -1000<=pushV[i]<=1000
- pushV 的所有数字均不相同
借助辅助栈,如果pushV[i] != popV[j],把pushV[i]压入辅助栈。若相等则i,j均后移,并判断辅助栈顶元素和popV[j]是否相等,相等继续弹出,直到i<pushV.size()。
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
stack<int> tmp;
int i=0, j=0;
while(i<pushV.size()){
if(pushV[i] != popV[j]){
tmp.push(pushV[i]);
i++;
}
else{
i++;
j++;
while(!tmp.empty() && tmp.top()==popV[j]){
tmp.pop();
j++;
}
}
}
return tmp.empty();
}
};
class Solution:
def __init__(self):
self.stack = []
def IsPopOrder(self , pushV: List[int], popV: List[int]) -> bool:
i = 0
j = 0
while i < len(pushV):
if pushV[i] != popV[j]:
self.stack.append(pushV[i])
i += 1
else:
i += 1
j += 1
while len(self.stack) and self.stack[len(self.stack)-1] == popV[j]:
j += 1
self.stack.remove(self.stack[len(self.stack)-1])
return len(self.stack)==0
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
数据范围:1≤n≤100
进阶:空间复杂度 O(n),时间复杂度O(n),保证没有只包含空格的字符串。
class Solution {
public:
string ReverseSentence(string str) {
string reverse;
stack<string> re;
string tmp = "";
int loc = 0;
for(int i = 0; i < str.length(); i++){
if(str[i] == ' '){
loc = i;
re.push(tmp);
tmp = "";
continue;
}
tmp += str[i];
}
if(loc == 0)
re.push(str.substr(loc, str.size()));
else
re.push(str.substr(loc+1, str.size()));
while(!re.empty()){
reverse += re.top() + ' ';
re.pop();
}
return reverse.substr(0, reverse.size()-1);
}
};
class Solution:
def ReverseSentence(self , str: str) -> str:
split = str.split(' ')
print(split)
reverse = ''
for i in range(len(split)-1, -1, -1):
reverse += split[i] + ' '
print(reverse)
return reverse[:-1]
JZ59 滑动窗口的最大值(困难)
给定一个长度为 n 的数组 nums 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。
例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
数据范围: 1≤size≤n≤10000,数组中每个元素的值满足∣val∣≤10000
要求:空间复杂度 O(n),时间复杂度 O(n)
我们要维护size大小的队列, 当进来一个比队尾元素要大的数时,要把队尾元素删除,他不可能成为后面的最大值;若对头的值超出滑动窗口,也要删除队头元素;队头元素一直为最大的,这个队列是个单调队列。
class Solution {
public:
vector<int> maxInWindows(const vector<int>& nums, int size) {
deque<int> q; // 存储的是元素位置信息
vector<int> result;
for(int i = 0; i< nums.size();i++){
// 队尾元素比新来的小,就会被替代
while(!q.empty() && nums[q.back()] < nums[i])
q.pop_back();
// 加入新来的元素位置
q.push_back(i);
// 如果队头的元素出窗口了,那么需要移除
if(q.front() < i-size+1){
q.pop_front();
}
// 大于窗口的才放入结果
if(i >= size-1){
result.push_back(nums[q.front()]);
}
}
return result;
}
};
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
stack = []
dequeue = []
for i in range(len(num)):
while len(dequeue) and num[dequeue[len(dequeue)-1]] < num[i]:
dequeue.remove(dequeue[len(dequeue)-1])
dequeue.append(i)
if dequeue[0] < i-size+1:
dequeue.remove(dequeue[0])
if i >= size-1:
stack.append(num[dequeue[0]])
return stack