今日任务:
- 理论基础
- 用栈实现队列
- 用队列实现栈
- 有效的括号
- 删除字符串中的所有相邻重复项
今天的题目都比较 easy,简单记录一下
用栈实现队列
栈实现队列的核心是,利用栈的先进后出的特性来实现,队列的先进先出,我们就需要定义两个栈,stackA 和 stackB 然后,如果是添加元素的话栈和队列是一样的,都是从后面进行添加,因此,添加我们直接放到 stackA 当中即可,如果是删除的话,栈是从后面删除,而队列要删除前面的元素,所以我们要借助另一个栈来帮助它删除,从 stackA 中后往前弹出元素,比如说 stackA 里面是 [1, 2, 3] 弹出,之后到 stackB 里面是 [3, 2, 1] 然后我们将 stackB.pop() 弹出的就是 1 也就是之前 stackA 中的队首元素,然后再把 stackB 里面中的元素弹出回到 stackA 当中即可,之后 stackA 就是 [2, 3]
(我没写 peek 方法,但是大致思路有了其它就是一些修改了)
Stack<E> stackA = new ArrayStack<>();
Stack<E> stackB = new ArrayStack<>();
public void offer(E e) {
stackA.push(e);
}
public E poll() {
//弹出需要借助stackB来执行
while (!stackA.isEmpty()) {
stackB.push(stackA.pop());
}
E ret = stackB.pop();
while (!stackB.isEmpty()) {
stackA.push(stackB.pop());
}
return ret;
}
public void clear() {
stackA.clear();
}
public void size() {
stackA.size();
}
public void isEmpty() {
stackA.isEmpty();
}
用队列实现栈
队列实现栈和栈实现队列是有一些不一样的,这是根据它们自身的特性来的,如果添加就直接在后面进行添加,这个没有争议,但是如果删除的话,队列是要删除前面的元素,但是栈希望实现的是删除后面的元素,因此也要借助另一个队列来实现删除操作 queueA [1, 2, 3] 删除后面的元素 3 我们将 queueB 进行弹出,从前往后,如果全部弹出的话 queueB 就是 [1, 2, 3] 还是无法删除 3 因此我们就将 queueA 弹出 size - 1 个元素,剩下的 3 作为队首元素,删除,如果添加在 queueB 中直接添加,如果删除将 queueB 中的元素移动到 queueA 中,也是只保留一个元素即可,所以我们可以看到栈实现队列和队列实现栈的一处不同在于,栈实现队列每次操作都需要移动元素从 stackA 到 stackB,但是队列实现栈的话就是两个队列随机,一个慢一个空这样,如果删除元素的话才移动,并不固定,添加元素比较 random
Queue<E> queueA = new ArrayQueue<>();
Queue<E> queueB = new ArrayQueue<>();
public void push(E element) {
if (!queueA.isEmpty()) {
queueA.offer(element);
} else if (!queueB.isEmpty()) {
queueB.offer(element);
} else {//如果都为空就添加到queueA里面
queueA.offer(element);
}
}
public E pop() {
if (size() == 0) {
throw new IllegalArgumentException("queue is empty");
}
if (!queueA.isEmpty()) {
while (queueA.size() != 1) {
queueB.offer(queueA.poll());
}
return queueA.poll();
} else {
while (queueB.size() != 1) {
queueA.offer(queueB.poll());
}
return queueB.poll();
}
//然后删除
}
public int size() {
return queueA.size() + queueB.size();
}
public boolean isEmpty() {
return queueA.isEmpty() && queueB.isEmpty();
}
public void clear() {
queueA.clear();
queueB.clear();
}
有效括号
有效括号是栈的一个应用,这类题目,如果是用其它解法会很复杂,我也想不到,但是这种括号匹配问题用栈来做最为方便,思路也比较简单,这里我们借助了一个 hashMap,遍历提供的字符串,如果不是 ) } ] 这种的话就直接添加到栈中,如果是的话,在判断栈不为空的情况下(如果不判断的话,弹出栈顶元素可能会导致空指针),我们就需要弹出栈顶元素,如果比如我们弹出 ( 如果和 hashMap.get(')') 的值 ( 不相等的话,就说明他这个不是闭合的,直接返回 false 即可,当然我们给的这个肯定是闭合的,我是说,如果 字符串遍历到比如说 } 然后,我们弹出的栈顶元素是这个 ( 那么 (} 肯定是不闭合的,因此就返回 false,当然如果给的字符串只有一个元素,比如说 ) 这时候它也不会进入到 stack 中,如果不做空判断的话,直接 stack.pop() 就报空指针异常了!
public boolean isValid(String s) {
//定义一个栈,和一个 HashMap
//栈中存放 ( [ { 而 HashMap 当中存放 )( ][ }{ 键值对
Map<Character, Character> hashMap = new HashMap();
hashMap.put(')', '(');
hashMap.put(']', '[');
hashMap.put('}', '{');
Stack<Character> stack = new Stack();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (hashMap.containsKey(c)) {
if (!stack.isEmpty()) {
Character ch = stack.pop();
if (!ch.equals(hashMap.get(c))) {
return false;
}
} else {
return false;
}
} else {
stack.push(c);
}
}
if (stack.isEmpty()) {
return true;
} else {
return false;
}
}
删除字符串中的所有相邻重复项
这个和上面的类似,注意 !stack.isEmpty() 判断即可!
public String removeDuplicates(String s) {
Stack<Character> stack = new Stack();
for (int i = 0; i < s.length(); i++) {
if (!stack.isEmpty() && stack.peek().equals(s.charAt(i))) {
stack.pop();
} else {
stack.push(s.charAt(i));
}
}
StringBuilder sb = new StringBuilder();
while(!stack.isEmpty()) {
sb.append(stack.pop());
}
return sb.reverse().toString();
}
总结:
栈的应用可以很方便的解决这类删除相邻重复项,括号匹配问题,如果遇到这类问题,想一想可不可以利用栈这种数据结构的特性来解决,栈转队列和队列转栈比较考察对它们两个数据结构特性的掌握。