今天看啥  ›  专栏  ›  coder_yangz

Queue&Stack

coder_yangz  · 掘金  ·  · 2020-02-16 08:00
阅读 31

Queue&Stack

Queue&Stack

Stack

Stack 一种后进先出(LIFO)的线性表.

栈的操作很简单。只要是具有最近相关性的题目都可以使用Stack这种数据结构来解决。

需要注意的是可以用Stack解决的问题都可以使用Deque(Double End Queue)来代替.

Stack相关LeetCode 题目

1.括号匹配

class Solution {

 Map<Character,Character> mappings;
 public Solution() {
    this.mappings = new HashMap<Character, Character>();
    this.mappings.put(')', '(');
    this.mappings.put('}', '{');
    this.mappings.put(']', '[');
  }

//stack里边存储的一定是有括号   如果map get到左括号 就比较 没有就push
public boolean isValid(String s) {
    if(s == null || (s.length() % 2) == 1) {
        return false;
    }
   Stack<Character> stack = new Stack<>();
   for(int i = 0 ; i < s.length() ;i++ ) {
       Character c = s.charAt(i);
       Character cc = mappings.get(c);
       if(cc != null) {
           Character topEle = stack.empty() ? '#' : stack.pop();
           if(! topEle.equals(cc)) {
               return false;
           }
       }else {
           stack.push(c);
       }
   }
   return stack.isEmpty();
}


复制代码

2最小栈

使用了aider 栈保存了当前的最小值,以及在此之前的最小值。

class MinStack {

    private Stack<Integer> data;

    private Stack<Integer> aider;

    /** initialize your data structure here. */
    public MinStack() {
        data = new Stack<>();
        aider = new Stack<>();

    }

    public void push(int x) {
        data.push(x);
        if(aider.isEmpty() || aider.peek() >= x) {
            aider.push(x);
        }
    }

    public void pop() {
        if(!data.isEmpty()) {
            int x =data.pop();
            if(x == aider.peek()) {
                aider.pop();
            }
        }
    }

    public int top() {
        if(!data.isEmpty()) {
            return data.peek();
        }
        throw  new RuntimeException("data is empty");
    }

    public int getMin() {
        if(!aider.isEmpty()) {
            return aider.peek();
        }
        throw new RuntimeException("aider is empty");
    }
}
复制代码

3.柱状图最大面积

使用栈辅助的,比当前栈顶元素大push如栈,小于栈顶元素则进行比较计算,栈顶元素的左边界为栈顶元素的上一个元素,有边界为当前小于栈顶元素的值。

 
 //解法一
 public int largestRectangleArea(int[] heights) {
        int maxArea = 0;
        Stack<Integer> leftBorder = new Stack<>();
        leftBorder.push(-1);
        for (int i = 0; i < heights.length; i++) {
            while(leftBorder.peek() != -1  && heights[leftBorder.peek()] > heights[i]) {
                maxArea = Math.max(maxArea,heights[leftBorder.pop()] * (i - 1 - leftBorder.peek()));
            }
            leftBorder.push(i);
        }

        while(leftBorder.peek() != -1){
            maxArea = Math.max(maxArea,heights[leftBorder.pop()] * (heights.length - 1 - leftBorder.peek()));
        }
        return maxArea;
    }


/**
     * 解决办法二分治算法
     *
     * @param heights
     * @return
     */
    public int largestRectangleArea4(int[] heights) {
        if (heights.length == 0) {
            return 0;
        }
        return largestRecusion(heights, 0, heights.length - 1, heights[0]);
    }

    private int largestRecusion(int[] heights, int start, int end, int max) {
        if (start >= end) {
            return max;
        }
        int minIndex = getMinIndex(heights, start, end);

        int currentArea = heights[minIndex] * (end - start + 1);

        max = Math.max(max, currentArea);

        int max1 = largestRecusion(heights, start, minIndex - 1, heights[start]);
        int max2 = largestRecusion(heights, minIndex + 1, end, heights[end]);
        return Math.max(max, Math.max(max1, max2));
    }

    private int getMinIndex(int[] heights, int start, int end) {
        int min = Integer.MAX_VALUE;
        int minIndex = start;
        for (int i = start; i <= end; i++) {
            if (min > heights[i]) {
                min = heights[i];
                minIndex = i;
            }
        }
        return minIndex;
    }

复制代码

Queue

队列的种类很多

  • 队列
  • 环形队列
  • 阻塞队列
  • 优先级队列
  • 并发队列
  • ...等等

Queue也是一种线性表,特性就是先进先出(FIFO).

Queue代码分析

Queue是一个接口,有六个方法

-throw Exception- -return default result -
add(E e) offer(E e) 添加元素(head)
remove() poll() 删除元素(head)
element() peek() 获取元素(head)
public interface Queue<E> extends Collection<E> {
   
    boolean add(E e);
   
    boolean offer(E e);

    E remove();

    E poll();

    E element();

    E peek();
}
复制代码

自己实现一个双端环形队列

class MyCircularDeque {

     private int[] elements;
    private int head;
    private int tail;
    private int len;

    /**
     * Initialize your data structure here. Set the size of the deque to be k.
     */
    public MyCircularDeque(int k) {
        this.elements = new int[k + 1];
        len = k + 1;
    }

    /**
     * Adds an item at the front of Deque. Return true if the operation is successful.
     */
    public boolean insertFront(int value) {
        if (isFull()) {
            return false;
        }
        elements[head = (head - 1 + len) % len] = value;
        return true;
    }

    /**
     * Adds an item at the rear of Deque. Return true if the operation is successful.
     */
    public boolean insertLast(int value) {
        if (isFull()) {
            return false;
        }
        elements[tail] = value;
        tail = (tail + 1) % len;
        return true;
    }

    /**
     * Deletes an item from the front of Deque. Return true if the operation is successful.
     */
    public boolean deleteFront() {
        if (isEmpty()) {
            return false;
        }
        head = (head + 1) % len;
        return true;
    }

    /**
     * Deletes an item from the rear of Deque. Return true if the operation is successful.
     */
    public boolean deleteLast() {
        if (isEmpty()) {
            return false;
        }
        tail = (tail - 1 + len) % len;
        return true;
    }

    /**
     * Get the front item from the deque.
     */
    public int getFront() {
        if(isEmpty()) {
            return -1;
        }
        return elements[head];
    }

    /**
     * Get the last item from the deque.
     */
    public int getRear() {
        if(isEmpty()) {
            return -1;
        }
        return elements[(tail - 1 + len) % len];
    }

    /**
     * Checks whether the circular deque is empty or not.
     */
    public boolean isEmpty() {
        return (head == tail);
    }

    /**
     * Checks whether the circular deque is full or not.
     */
    public boolean isFull() {
        return ((tail + 1) % len) == head;
    }


}
复制代码

Priority Queue代码分析

java的Priority Queue 是依靠heap(小顶堆)来进行存储数据的,它的核心代码就是建堆的操作,主要就是Priority Queue 的两个方法 add()pop()

add(),代码分析 siftUp(由下向上建堆)。代码注释如下。

	/**
	* 添加代元素
	*/
	public boolean add(E e) {
        return offer(e);
    }

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
  			//如果队列满了 扩容
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
          //新添加的元素从下向上进行堆化
            siftUp(i, e);
        return true;
    }
		private void siftUp(int k, E x) {
        if (comparator != null)
          //自定义比较器
            siftUpUsingComparator(k, x);
        else
          //默认比较器
            siftUpComparable(k, x);
    }

    @SuppressWarnings("unchecked")
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
          	//堆元素的父亲节点的索引
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
          	//比较与父亲节点的大小,因为是小顶堆如果 小于父亲元素交换,大于结束。
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }
复制代码

poll() 的代码其实就是删除他的heap顶元素并且返回。满足删除条件的情况下,进行由上向下堆化的过程,代码如下。

	public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }

 private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

    @SuppressWarnings("unchecked")
    private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }
复制代码



原文地址:访问原文地址
快照地址: 访问文章快照