今天开始学习栈和队列,第一天的题目都较为简单,用栈模拟队列,用队列模拟栈,以及一道栈的经典应用题目。
LeetCode232.用栈实现队列
本题和后面一题都锻炼了对栈和队列特点的运用。栈是先入后出,队列是先入先出,如果他们的进入顺序相同,退出的顺序将会是相反的。既然如此,结合题目使用两个栈,那么我们很容易可以想到,否定之否定为肯定,即二次取反不会改变原来的顺序。具体来说就是,如果出队的顺序为原顺序,那么出栈的顺序将会颠倒,编程相反的顺序,那么再进行一次出栈,再次颠倒,就会编程原来的出队顺序。理论成立,我们可以开始模拟,在模拟的时候,会发现有另外一种情况,当栈内元素没有出干净,这时入栈,将会打乱原有顺序,需要我们再次思考,应该怎么调配这些元素,使他们顺序保持不变。
public class MyQueue {
static Stack<Integer> stack1;
static Stack<Integer> stack2;
public MyQueue(){
stack1=new Stack<>();
stack2=new Stack<>();
}
public static void push(int x){
stack1.push(x);
}
public static int pop(){
if (stack2.isEmpty()){
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
public static int peek(){
if (stack2.isEmpty()){
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.peek();
}
public static boolean empty(){
if (stack1.empty()&& stack2.empty()){
return true;
}else {
return false;
}
}
}
我们定义两个栈,stack1为入队栈,stack2为出队栈,入队时,将元素push进入队栈即可。在出队时,需要注意顺序,首先将入队栈的每个元素出栈后再次push进出队栈,这样顺序就会恢复进入的顺序。之后考虑特殊情况,即如果没出干净就进栈,将会打乱顺序,所以我们可以将stack1当作存储区,如果stack2中没有元素,即可以将stack1中的元素push进stack2中,如果stack2中仍留有元素,则入队的元素先存在stack1中,当stack2中为空时,将stack1中的所有元素push进stack2中,即可解决该问题。最后两个操作较简单,不作过多阐述。
LeetCode225.用队列实现栈
与上题题目基本类似,只不过这次是使用队列来实现栈。在这里我同样使用连两个队列来完成栈的操作。这次的基本思路是,始终留一个队列为空,每次进栈的元素都push进空的队列,然后再将另一个队列的每一个元素进行出队操作,依次进入这个原本为空的队列,这样原来不为空的队列将会为空,空队列将存在元素,如此循环,用队列实现入栈出栈的操作。
public class MyStack {
static Queue<Integer> queue1;
static Queue<Integer> queue2;
public MyStack(){
queue1=new LinkedList<>();
queue2=new LinkedList<>();
}
public static void push(int x){
if (queue1.isEmpty()){
queue1.offer(x);
while (!queue2.isEmpty()){
queue1.offer(queue2.poll());
}
} else if (queue2.isEmpty()) {
queue2.offer(x);
while (!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
}
}
public static int pop(){
if(queue1.isEmpty()){
return queue2.poll();
}else {
return queue1.poll();
}
}
public static int top(){
if(queue1.isEmpty()){
return queue2.peek();
}else {
return queue1.peek();
}
}
public static boolean empty(){
if (queue1.isEmpty()&& queue2.isEmpty()){
return true;
}else {
return false;
}
}
}
LeetCode20.有效的括号
这是一道非常经典的应用栈的题目,在第一次学数据结构的时候,就遇到了该问题,这道题第一次还是使用c语言完成的,这次就使用java来实现。
首先,题目明确说明,只出现(){}[]
这六种字符,不会出现别的字符,那么如此我们可以只关注这六种字符,如果遇到左括号,我们可以将其存如栈,如果遇到右括号,栈顶元素出栈,判断两者是否匹配,如果匹配继续操作,如果不匹配则说明不是有效括号,返回错误信息即可。注意,如果碰到右括号,而栈内为空,出栈将会报错,所以在出栈之前,先判断是否为空,如果为空,则说明先出现右括号,没有左括号,不是有效括号,如果不为空,才进行出栈匹配的操作。最后,当字符串遍历完成后,如果栈内不为空,说明有多出来的左括号没有被匹配掉,也不是有效的括号。如果以上都正确,最后将说明这是一个有效括号,返回正确信息即可。注意,这里if条件判断较多,但是并不难思考,细心将每一种情况思考完成后,即可完成本题。
public static boolean isValid(String s){
Stack<Character> stack=new Stack<>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i)=='['||s.charAt(i)=='('||s.charAt(i)=='{'){
stack.push(s.charAt(i));
continue;
}
if (s.charAt(i)==']') {
if (stack.isEmpty()){
return false;
}else {
if (stack.pop()!='['){
return false;
}
}
}
if (s.charAt(i)=='}') {
if (stack.isEmpty()){
return false;
}else {
if (stack.pop()!='{'){
return false;
}
}
}
if (s.charAt(i)==')') {
if (stack.isEmpty()){
return false;
}else {
if (stack.pop()!='('){
return false;
}
}
}
}
if (stack.isEmpty()){
return true;
}else {
return false;
}
}