用两个栈实现队列
刷题链接:
https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6
题目描述
思路一:
使用两个栈来实现队列的功能。栈 1 用于存储入队的元素,而栈 2 用于存储出队的元素。
1.push方法将元素压入栈 1。
2.pop方法首先检查栈 2 是否为空。如果为空,则将栈 1 中的所有元素移到栈 2。然后,弹出栈 2 中的顶部元素并返回。
复杂度分析
时间复杂度:在最坏情况下,pop 操作的时间复杂度是 O(n),但在平均情况下,当栈2中有元素时,pop 操作的时间复杂度是 O(1)。这是因为在平均情况下,元素不会每次都从栈1移动到栈2。总体而言,这个实现的 push 操作是 O(1),而 pop 操作的最坏情况下是 O(n),平均情况下是 O(1)。
空间复杂度: O(n),辅助栈的空间,最差的情况下两个栈共存储N个元素。
python3
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, x: int) -> None:
# 入队时直接将元素压入 stack1
self.stack1.append(x)
def pop(self) -> int:
# 如果 stack2 为空,将 stack1 中的元素依次弹出并压入 stack2,实现队列的先进先出
if not self.stack2:
while self.stack1:
self.stack2.append(self.stack1.pop())
# 弹出 stack2 的栈顶元素,即队列头部的元素
return self.stack2.pop()
C++
class Solution {
public:
// 入队操作,将元素压入 stack1
void push(int x) {
stack1.push(x);
}
// 出队操作,实现队列的先进先出
int pop() {
// 如果 stack2 为空,将 stack1 中的元素依次弹出并压入 stack2
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
// 弹出 stack2 的栈顶元素,即队列头部的元素
int frontElement = stack2.top();
stack2.pop();
return frontElement;
}
private:
stack<int> stack1;
stack<int> stack2;
};
包含min函数的栈
刷题链接:
https://www.nowcoder.com/practice/4c776177d2c04c2494f2555c9fcc1e49
题目描述
思路一:
使用两个栈,一个用于存储元素,另一个用于存储当前栈中的最小元素。在 push 操作中,如果新元素小于等于辅助栈中的最小元素,则将其也压入辅助栈。在 pop 操作中,如果弹出的元素等于辅助栈中的最小元素,则也弹出辅助栈中的最小元素。top 和 min 函数分别返回主栈和辅助栈的栈顶元素。
复杂度分析
时间复杂度:O(1),所有操作的时间复杂度都是 O(1),因此整个代码的时间复杂度为 O(1)
空间复杂度: O(n),使用了两个栈,即 stack 和 min_stack,用于存储元素和维护最小元素。每个栈的空间复杂度为 O(n),其中 n 是栈中元素的个数。
python3
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
# 主栈,用于存储元素
self.stack = []
# 辅助栈,用于存储当前栈中的最小元素
self.min_stack = []
def push(self, x: int) -> None:
# 将元素压入主栈
self.stack.append(x)
# 更新辅助栈,存储当前栈中的最小元素
if not self.min_stack or x <= self.min_stack[-1]:
self.min_stack.append(x)
def pop(self) -> None:
# 弹出主栈的栈顶元素
if self.stack:
popped_element = self.stack.pop()
# 如果弹出的元素是当前栈中的最小元素,则同时更新辅助栈
if popped_element == self.min_stack[-1]:
self.min_stack.pop()
def top(self):
# 返回主栈的栈顶元素
if self.stack:
return self.stack[-1]
def min(self):
# 返回当前栈中的最小元素
if self.min_stack:
return self.min_stack[-1]
C++
class Solution {
public:
void push(int value) {
stack.push(value);
if (min_stack.empty() || value <= min_stack.top()) {
min_stack.push(value);
}
}
void pop() {
if (!stack.empty()) {
int popped_element = stack.top();
stack.pop();
if (popped_element == min_stack.top()) {
min_stack.pop();
}
}
}
int top() {
if (!stack.empty()) {
return stack.top();
}
return -1;
}
int min() {
if (!min_stack.empty()) {
return min_stack.top();
}
return -1;
}
private:
std::stack<int> stack;
std::stack<int> min_stack;
};
栈的压入、弹出序列
刷题链接:
https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106
题目描述
思路一:
使用一个辅助栈,遍历压栈序列,并在每次压入一个元素后检查是否需要弹出栈顶元素,直到弹出序列的当前元素与栈顶元素不相同时停止。最后,如果栈为空,说明给定的弹出序列是可能的;否则,不可能。
复杂度分析
时间复杂度:O(n),最坏情况下需要遍历两个数组各一次;
空间复杂度:O(n),辅助栈空间最大为一个数组的长度;
python3
class Solution:
def IsPopOrder(self, pushV: List[int], popV: List[int]) -> bool:
if not pushV or not popV:
return False
stack = [] # 辅助栈,用于模拟压入和弹出操作
idx = 0 # 弹出序列的索引
for num in pushV:
stack.append(num) # 将当前元素压入栈
# 循环检查栈顶元素是否需要弹出
while stack and stack[-1] == popV[idx]:
stack.pop() # 弹出栈顶元素
idx += 1 # 移动到下一个弹出元素
# 如果栈为空,说明给定的弹出序列是可能的;否则,不可能
return not stack
C++
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pushV int整型vector
* @param popV int整型vector
* @return bool布尔型
*/
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
if (pushV.empty() || popV.empty()) {
return false;
}
stack<int> stk; // 辅助栈,用于模拟压入和弹出操作
int idx = 0; // 弹出序列的索引
for (int num : pushV) {
stk.push(num); // 将当前元素压入栈
// 循环检查栈顶元素是否需要弹出
while (!stk.empty() && stk.top() == popV[idx]) {
stk.pop(); // 弹出栈顶元素
idx++; // 移动到下一个弹出元素
}
}
// 如果栈为空,说明给定的弹出序列是可能的;否则,不可能
return stk.empty();
}
};
翻转单词序列
刷题链接:
https://www.nowcoder.com/practice/3194a4f4cf814f63919d0790578d51f3
题目描述
思路一:
直接法:将字符串按空格进行切分,然后进行逆序拼接。
复杂度分析
时间复杂度:O(n),只需对列表进行一次切分,再按要求进行拼接;
空间复杂度:O(n),单词列表占用线性大小的额外空间;
python3
class Solution:
def ReverseSentence(self , str: str) -> str:
# 将字符串按空格分割为单词列表
words = str.split()
# 逆序遍历单词列表并拼接成新的字符串
reversed_str = ""
for i in range(len(words) - 1, -1, -1):
reversed_str += words[i]
if i > 0:
reversed_str += " " # 在单词之间添加空格
return reversed_str
C++
class Solution {
public:
string ReverseSentence(string str) {
string result;
// 使用字符串流按空格分割原句子
stringstream ss(str);
string word;
// 从流中读取单词并逆序拼接到结果字符串中
while (ss >> word) {
if (!result.empty()) {
result = word + " " + result;
} else {
result = word;
}
}
return result;
}
};
滑动窗口的最大值
刷题链接:
https://www.nowcoder.com/practice/1624bc35a45c42c0bc17d17fa0cba788
题目描述
思路一:
暴力法:直接遍历两层:第一层为窗口起点,第二层为窗口长度,即遍历了所有的窗口的每个位置。
复杂度分析
时间复杂度:O(n*m),双层for循环,n为数组长度,m为窗口长度;
空间复杂度:O(n),结果res占用线性大小的空间;
python3
class Solution:
def maxInWindows(self , num: List[int], size: int) -> List[int]:
n = len(num)
if not num or size <= 0 or size > n:
return []
res = []
for i in range(n-size+1):
tmp = max(num[i:i+size])
res.append(tmp)
return res
C++
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型vector
* @param size int整型
* @return int整型vector
*/
vector<int> maxInWindows(vector<int>& num, int size) {
int n = num.size();
vector<int> res;
if (num.empty() || size <= 0 || size > n) {
return res;
}
for (int i = 0; i <= n - size; ++i) {
int tmp = *max_element(num.begin() + i, num.begin() + i + size);
res.push_back(tmp);
}
return res;
}
};