剑指offer 09、30:栈与队列

目录

    • 1.栈与队列详解
      • 1.栈
      • 2.队列
    • 2.剑指offer09:用两个栈实现队列
      • 1.题目描述
      • 2.题目解析
          • 我的思路:
          • 大佬思路:
          • 自己实现大佬思路:
    • 3.剑指offer30:用包含min的栈
      • 1.题目描述
      • 2.题目解析
          • 我的思路:
          • 实现:
    • 4.总结

1.栈与队列详解

1.栈

这两篇博客讲得很详细:Java栈详解
C++栈详解
我总结一下:

  1. 栈是只能从一端进行元素的添加和删除的操作受限的线性表,可以用线性表和链表手动实现;线性存储结构;栈中元素遵循先进后出"(First In Last Out)的原则,简称FILO结构;只能在栈顶进行插入和删除操作。
  2. 栈的相关概念:
    栈顶与栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底。
    压栈:栈的插入操作,叫做进栈,也称压栈、入栈。
    弹栈:栈的删除操作,也叫做出栈。
  3. Java标准栈Stack
Stack<T>mystack=new Stack<T>();//定义
public boolean isEmpty()//判断栈是否为空
public int getLength()//获取栈中元素的个数
public void push(T t)//压栈(向栈顶放入元素)
public T pop()//出栈(拿出栈顶元素,并得到它的值)
public T getHeadNext()//获取栈顶元素(未拿出)
public boolean contains(T t)//判断栈中是否包含该元素
  1. C++标准栈:stack
    包含头文件: #include< stack >
stack< int > s;    //定义
s.empty();         //如果栈为空则返回true, 否则返回false;
s.size();          //返回栈中元素的个数
s.top();           //返回栈顶元素, 但不删除该元素
s.pop();           //弹出栈顶元素, 但不返回其值
s.push();          //将元素压入栈顶

2.队列

  1. 队列是先进先出(First In First Out)FIFO的线性存储结构;可以使用顺序存储和链式存储手动实现;只允许在队首删除元素,在队尾插入元素。
  2. 在java中队列有两种实现方式:循环数组ArrayDeque和链表LinkedList
    java实现Queue
//新建
Queue<T> queue = new LinkedList<>();
//添加元素
queue.offer(T1);
//删除元素
queue.poll(T1);
//查看队首元素
queue.peek();

offer,add 区别:

一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。

这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。

poll,remove 区别:

remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似, 但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。

peek,element区别:

element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。

2.剑指offer09:用两个栈实现队列

1.题目描述

剑指offer 09、30:栈与队列_第1张图片

2.题目解析

我的思路:

1.栈为先进后出,队列是先进先出,所以可以使用一个栈A存储数据,在删除队列元素时将栈内所有元素倒序入另一个栈B,然后去除栈顶元素将所有元素倒入栈A。
2.java实现:

class CQueue {

    Stack<Integer>ru;
    Stack<Integer>chu;

    public CQueue() {
        ru=new Stack<Integer>();
        chu=new Stack<Integer>();
    }
    
    public void appendTail(int value) {
        ru.push(new Integer(value));
    }
    public int deleteHead() {
        if(ru.empty())
            return -1;
        while(!ru.empty())
        {
            Integer tem=ru.pop();
            chu.push(tem);
        }
        int res=chu.pop();
        while(!chu.empty())
        {
            Integer tem=chu.pop();
            ru.push(tem);
        }
        return res;
    }
}

结果:
剑指offer 09、30:栈与队列_第2张图片
可以看到不高效,因为每次除去队列首元素时都进行了两次倾倒动作。

大佬思路:

一个栈A接收元素,然后删除队首元素时,将所有元素倒入另一个栈B,去除B栈顶元素即为去除队列首元素。以后再添加元素即加入A栈顶即可,删除元素时需要看B:

  • 若B中还有元素,直接去除栈顶元素即可;
  • 若B中无元素A中有元素,直接将A中所有元素入B,然后再去除栈顶元素;
  • 若AB中均无元素,直接返回-1。
class CQueue {
    LinkedList<Integer> A, B;
    public CQueue() {
        A = new LinkedList<Integer>();
        B = new LinkedList<Integer>();
    }
    public void appendTail(int value) {
        A.addLast(value);
    }
    public int deleteHead() {
        if(!B.isEmpty()) return B.removeLast();
        if(A.isEmpty()) return -1;
        while(!A.isEmpty())
            B.addLast(A.removeLast());
        return B.removeLast();
    }
}

// 作者:jyd
// 链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/solution/mian-shi-ti-09-yong-liang-ge-zhan-shi-xian-dui-l-2/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
自己实现大佬思路:
class CQueue {
    Stack<Integer>a,b;
    public CQueue() {
        a=new Stack<Integer>();
        b=new Stack<Integer>();
    }
    
    public void appendTail(int value) {
        a.push(new Integer(value));
    }
    
    public int deleteHead() {
        if(!b.empty())
        {
            return b.pop();
        }
        else if(!a.empty())
        {
            while(!a.empty())
            {
                Integer temp=a.pop();
                b.push(temp);
            }
            return b.pop();
        }
        else
            return -1;
    }
}

剑指offer 09、30:栈与队列_第3张图片

3.剑指offer30:用包含min的栈

1.题目描述

剑指offer 09、30:栈与队列_第4张图片

2.题目解析

我的思路:

第一眼看到时就想拿个int存储最小值,但是最小值去除之后再找最小值就难以操作,需要记录第二小的值。
于是我查看了题解,只需要一个辅助栈存储逆序的值即可,关键是因为栈的特性,已存在的数据位置不会改变,所以只需存储从第一个元素开始的严格逆序的元素即可。

实现:
class MinStack {

    Stack<Integer>st;
    Stack<Integer>helpst;
    /** initialize your data structure here. */
    public MinStack() {
        st=new Stack<Integer>();
        helpst=new Stack<Integer>();
    }
    
    public void push(int x) {
        st.push(new Integer(x));
        if(helpst.empty())
        {
            helpst.push(new Integer(x));
            return;
        }
        if(x<=helpst.peek().intValue())
            helpst.push(new Integer(x));
    }
    
    public void pop() {
        int temp=st.pop();
        if(temp==helpst.peek().intValue())
            helpst.pop();

    }
    
    public int top() {
        return st.peek().intValue();
    }
    
    public int min() {
        return helpst.peek().intValue();

    }
}

剑指offer 09、30:栈与队列_第5张图片

4.总结

1.我好像没有深入理解栈与队列的特性,比如第二题中,辅助栈只需存储逆序元素即可,我还反应了好一会儿才明白;
2.编程手感要一直练才会存在。
3.参考:
java队列
java栈

你可能感兴趣的:(力扣题目练习,leetcode,算法,职场和发展)