1、栈与队列理论基础
栈和队列的原理大家应该很熟悉,队列是先进先出,栈是先进后出。对于队列和栈,它们的操作是受限的,队列只能在一端插入元素,另一端删除元素;栈只能从某一端插入和删除元素。
这两种数据结构的API如下:
// 队列的基本 API
class MyQueue<E> {
// 向队尾插入元素,时间复杂度 O(1)
void push(E e);
// 从队头删除元素,时间复杂度 O(1)
E pop();
// 查看队头元素,时间复杂度 O(1)
E peek();
// 返回队列中的元素个数,时间复杂度 O(1)
int size();
}
// 栈的基本 API
class MyStack<E> {
// 向栈顶插入元素,时间复杂度 O(1)
void push(E e);
// 从栈顶删除元素,时间复杂度 O(1)
E pop();
// 查看栈顶元素,时间复杂度 O(1)
E peek();
// 返回栈中的元素个数,时间复杂度 O(1)
int size();
}
2、题目1:232-用栈实现队列
类型:简单
思路:在 push 数据的时候,只要数据放进输入栈就好,但在 pop 的时候,操作就复杂一些,输出栈如果为空,就把入栈的数据猼导入进来,再从输出栈弹出数据,如果输出栈不为空,则直接从输出栈弹出数据。
如果进栈和出栈都为空的话,说明模拟的队列为空。
public 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(){
if(stackOut.isEmpty()){
while (!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
public int peek(){
if(stackOut.isEmpty()){
while (!stackIn.isEmpty()){
stackOut.push(stackIn.pop());
}
}
return stackOut.peek();
}
public boolean empty(){
return stackIn.isEmpty() && stackOut.isEmpty();
}
}
3、题目2:225-用队列实现栈
类型:简单
思路:一个队列在模拟栈弹出元素的时候,只要将队列头部的元素(除了最后一个元素外)重新添加到队列尾部,此时再取弹出元素就算栈的顺序了。
public class MyStack {
Queue<Integer> queue;
public MyStack(){
queue = new LinkedList<>();
}
// 入栈
public void push(int x){
queue.add(x);
}
// 移除栈顶元素
public int pop(){
rePosition();
return queue.poll();
}
public int top(){
rePosition();
int result = queue.poll();
queue.add(result);
return result;
}
public boolean empty(){
return queue.isEmpty();
}
private void rePosition() {
int size = queue.size();
size--;
while (size > 0){
queue.add(queue.poll()); // 队列首部元素移动到末尾
size--;
}
}
}
4、题目3:20-有效的括号
给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
public static boolean isValid(String s) {
HashMap<Character, Character> map = new HashMap<>();
map.put('{','}');
map.put('(',')');
map.put('[',']');
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if(map.containsKey(c)){
stack.add(c);
}else{
if(stack.isEmpty() || !map.get(stack.pop()).equals(c)){
return false;
}
}
}
//剩余的单个元素没找到对象
if(stack.size()>0){
return false;
}
return true;
}
5、题目4:1047-删除字符串中的所有相邻重复项
类型:简单
示例:
输入: "abbaca" 输出: "ca" 解释: 例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
思路很简单,就是栈实现,每放入一个元素,就从栈中取出元素判断是否相等,如果相等就出栈,直到没有重复的元素。
public static String removeDuplicates(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
judgeStackDuplicat(c, stack);
}
StringBuffer buffer = new StringBuffer();
for (Character c : stack) {
buffer.append(c);
}
return buffer.toString();
}
private static void judgeStackDuplicat(Character s, Stack<Character> stack) {
boolean falg = true;
while (stack.size()>0){
Character peek = stack.peek();
if(peek.equals(s)){
stack.pop();
falg = false;
}else{
break;
}
}
// 没有发生了移除元素的操作,那就可以放入这个元素
if(falg){
stack.add(s);
}
}