用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现 MyQueue 类:
- void push(int x) 将元素 x 推到队列的末尾
- int pop() 从队列的开头移除并返回元素
- int peek() 返回队列开头的元素
- boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
该题主要是已经提供了栈的一系列操作(说明中已经说明了),不需要自己去构建栈的一些列操作,我们只需要实现的是用两个栈来实现一个队列的操作,没有复杂度,需要注意的就是当stcakOut为空是,需要将stackIn中的元素放到stackOut中,总归还是两个单独操作的栈,而不是说是一个数组维护的两头插入的栈。
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
// 初始化队列通过两个栈来实现
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
// 看看是否stackOut为空,为空则将stackIn中的元素全部放到stackOut中
dumpStackIn();
return stackOut.pop();
}
public int peek() {
dumpStackIn();
return stackOut.peek();
}
public boolean empty() {
return stackIn.isEmpty() && stackOut.isEmpty();
}
// 如果stackOut为空,那么将stackIn中的元素全部放到stackOut中(stackIn中pop,然后stackOut中push)
private void dumpStackIn(){
if (!stackOut.isEmpty()) {
return;
}
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty() ;
*/
用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
- void push(int x) 将元素 x 压入栈顶。
- int pop() 移除并返回栈顶元素。
- int top() 返回栈顶元素。
- boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
怎么去实现呢,我的理解是队列queueOne和queueTwo两个队列,每当要进栈,就进到有数据那个队列,每当要出栈,就将有数据的对列出队列,另一个队列进队列,直到第一个队列只剩一个元素,然后取出来。
优化:每当要进栈,就进到有数据那个队列 -------- > 可以每次确定进到queueOne中去
class MyStack {
Queue<Integer> q1;
Queue<Integer> q2; // 辅助队列,用来备份
public MyStack() {
q1 = new LinkedList<>();
q2 = new LinkedList<>();
}
public void push(int x) {
q1.offer(x);
}
public int pop() {
while (q1.size() > 1) { // 将q1 导入q2,但要留下最后一个元素
q2.offer(q1.poll());
}
int result = q1.poll(); // 留下的最后一个元素就是要返回的值
q1.addAll(q2); // 再将q2赋值给q1
q2.clear(); // 清空q2
return result;
}
public int top() {
int result = pop();
q1.offer(result);
return result;
}
public boolean empty() {
return q1.isEmpty();
}
}
这个双队列方法,其实卡尔哥的方法也挺好的,就是每次都构造一个栈,将新插入的元素放入queueOne中的队首。
class MyStack {
Queue<Integer> queue1; // 和栈中保持一样元素的队列
Queue<Integer> queue2; // 辅助队列
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x); // 先放在辅助队列中
while (!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> queueTemp;
queueTemp = queue1;
queue1 = queue2;
queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
该题不涉及算法,也不需要我们去构建队列,但是我们需要掌握java中队列的一些操作。其实我们了很多都还不太熟练:
同时,由于Queue类实现了Collection接口,也就可以使用Collection的一些方法。
队列的构造函数也需要了解,由于Queue是一个接口,我们需要调用它的实现类的构造方法来进行实例化(这里使用的是LinkList,也可以使用比其他的方法):
后面也可以补充单队列来实现。
有效的括号
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
思路就是使用栈,当进入的字符是‘(’、‘{’、 '['时,我们将对应的闭括号入栈,当我们字符串遍历到的字符是右括号时,我们将它和栈顶元素作比较,如果不同则错了。对了则出栈,继续遍历。
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
int i = 0;
while (i < s.length()) {
if (s.charAt(i) == '(') {
stack.push(')');
}else if (s.charAt(i) == '[') {
stack.push(']');
}else if (s.charAt(i) == '{') {
stack.push('}');
}else if (stack.isEmpty() || s.charAt(i) != stack.pop()){
return false;
}
i++;
}
return stack.isEmpty();
}
}
需要注意的就是我们栈对象的生成需要泛型,也就是栈中存放什么类型的数据。