码迷,mamicode.com
首页 > 编程语言 > 详细

栈和队列常见题型(java版)

时间:2015-07-26 22:45:25      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:java   数据结构   算法   

直接上干货。。。。。

栈和队列常见题型:

  1. 实现栈和实现队列。
  2. 两个栈实现一个队列。
  3. 设计栈,使得pop,push和min时间复杂度为O(1)。
  4. 滑动窗口的最大值。
  5. 栈的进出序列。

实现栈和实现队列

主要包括:栈,队列,循环队列。


package com.sywyg;

/**
 * 实现栈
 * 数组应该是Object类型的
 * 注意top的设置影响出栈和获取栈顶元素。
 * size也可以用top代替
 */
class MyStack<E>{
    // 栈元素个数
    private int size;
    // 栈头
    private int top;
    // 数组保存元素
    private Object[] stack = null;
    public MyStack(int length){
        stack = new Object[length];
        top = 0;
    }
    public int size(){
        return size;
    }
    // 进栈
    public void push(E e){
        if(size == stack.length){
            try{
                throw new Exception("栈已满");
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
        stack[top++] = e;
        size++;
    }
    // 出栈
    public E pop(){
        E e = null;
        if(size == 0){
            try{
                throw new Exception("栈为空");
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
        e = (E)stack[--top];
        size--;
        return e;
    }
    // 获取栈顶元素
    public E top(){
        if(size == 0){
            try{
                throw new Exception("栈为空");
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        return (E)stack[top-1];
    }
}

/**
 * 创建队列,这种队列会造成假溢出
 */
class MyQueue<E>{
    // 队列长度
    private int size;
    // 队头
    private int front;
    // 队尾
    private int back;
    private Object[] queue;
    public MyQueue(int length){
        queue = new Object[length];
        size = 0;
        front = 0;
        back = 0;
    }

    public int size(){
        return size;
    }
    // 进队
    public void enqueue(E e){
        if(size == queue.length){
            try{
                throw new Exception("队已满");
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
            queue[back++] = e;
            size++;
    }
    // 出队
    public E dequeue(){
        E e = null;
        if(size == 0 || back == front){
            try{
                throw new Exception("队为空");
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
        e = (E)queue[front++];
        size--;
        return e;
    }
    // 返回队头
    public E front(){
        return (E)queue[front];
    }
    // 返回队尾?
    public E back(){
        return (E)queue[back - 1];
    }
}

/**
 * 循环队列,采用浪费一个位置(使用size可以保证全利用)
 * 这里不使用size标记队列的长度,尽管这种方式很简单
 */
class LoopQueue<E>{
    // 队头
    private int front;
    // 队尾
    private int back;
    private Object[] queue;
    public LoopQueue(int length){
        // 浪费一个
        queue = new Object[length + 1];
        front = 0;
        back = 0;
    }

    public int size(){
        return (back - front + queue.length)% queue.length;
    }
    // 进队
    public void enqueue(E e){
        if((front - back + queue.length)% queue.length == 1){
            try{
                throw new Exception("队已满");
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
        queue[back ++ % queue.length] = e;

    }
    // 出队
    public E dequeue(){
        E e = null;
         if(front == back){
            try{
                throw new Exception("队为空");
            }catch(Exception ex){
                ex.printStackTrace();
            }
         }
            e = (E)queue[front++ % queue.length];
        return e;
    }
    // 返回队头
    public E front(){
        return  (E)queue[front];
    }
    // 返回队尾?
    public E back(){
        return  (E)queue[(back - 1 + queue.length) % queue.length];
    }
}

两个栈实现一个队列

思想:一个栈A只进,一个栈B只出,B为空则A元素进入B,再出栈。


package com.sywyg;

/**
 * 两个栈实现一个队列。
 * 这样仍然会造成假溢出。
 * 
 *
 */
    public static class Solution<E>{
        // 应该在构造器中赋值。
        // stack1用来入队
        private Stack<E> stack1 = new Stack<E>();
        // stack2用来出队
        private Stack<E> stack2 = new Stack<E>();

        // 入队
        public void enqueue(E e){
            stack1.push(e);
            //System.out.println("此时stack1栈顶元素为:" + stack1.top());
        }

        // 出队
        public E dequeue(){
            E e = null;
            if(stack2.size() != 0){
                e = stack2.pop();
            }else if(stack1.size() != 0){
                int length = stack1.size();
                for(int i = 0;i<length;i++){
                    stack2.push(stack1.pop());
                    //System.out.println("此时stack2栈顶元素为:" + stack2.top());
                }
                e = stack2.pop();
            }
            return e;
        }
}

- 测试:进进出出,进出。
- 如何用两个队列实现一个栈。

#设计栈,使得pop,push和min时间复杂度为O(1)

思想:额外的栈A存放当前最小值,每当进来的值a小于/等于该栈顶值b时,a需要入栈A;出栈时若栈A的栈顶和刚出栈的元素相等时,则A也出栈。

```java

package com.sywyg;
import java.util.Stack;

/**
 * 设计栈,使得pop,push和min时间复杂度为O(1)。
 * 或者使用一个每个最小值再包含一个计数标记
 */
    public static class Solution<E>{
        private Stack<E> stack,stackMin;
        public Solution(){
            stack = new Stack<E>();
            stackMin = new Stack<E>();
        }
        // 入栈
        public void push(E e){
            stack.push(e);
            if(stackMin.isEmpty()){
                stackMin.push(e);
            }else if(stackMin.peek() >= e){
                stackMin.push(e);
            }
        }
        // 出栈
        public E pop(){
            E e = stack.pop();
            if(e == stackMin.peek()){
                stackMin.pop();
            }

        }
        // 返回最小
        public E min(){
            return stackMin.peek();
        }
}





<div class="se-preview-section-delimiter"></div>
  • 测试:小大大大小小,每次出栈判断是否正确。
  • 时间复杂度:O(1),空间复杂度O(n)

滑动窗口的最大值

给定一个数组,和滑动窗口的大小,计算每个窗口中的最大值。例如数组{1,2,3,4,5},窗口大小为3。那么共存在3个滑动窗口,它们的大小为:{3,4,5}。

思想:须用到上面的第2题和第3题,用两个能够O(1)时间内计算出最大值的栈实现队列。先进入3个(窗口大小),然后再依次进1出1个。在统计最大值的时候比较两个栈中的最大值即可,注意需要判断栈是否为空。


package com.sywyg;

import java.util.Stack;

/**
 * 滑动窗口的最大值。
 * @author sywyg
 * 测试
 */
public class Question4 {

    public static void main(String[] args) {
        int[] array = {2,3,4,2,6,5,2,1};
        int[] max = solution(array, 3);
        for (int i = 0; i < max.length; i++) {
            System.out.println(max[i]);
        }
    }


    public static int[] solution(int[] array,int size){
        int[] max = new int[array.length - size + 1];
        MyQueue<Integer> queue = new MyQueue<Integer>(); 
        int i = 0;
        for(i = 0; i<size; i++){
            queue.enqueue(array[i]);
        }
        int j = 0;
        // 先进一个
        max[j++] = queue.stack1.max();
        for(;i<array.length;i++){
            queue.dequeue();
            queue.enqueue(array[i]);
            // 两个栈中的最大值进行比较
            if(queue.stack2.stackMax.size() == 0 || queue.stack1.max() >= queue.stack2.max()){
                max[j++] = queue.stack1.max();
            }else
                max[j++] = queue.stack2.max();
        }
        return max;
    }

    /**
     * 两个栈实现队列
     */
    public static class MyQueue<E>{
        // 应该在构造器中赋值。
        // stack1用来入队
        public MyStack<E> stack1 = new MyStack<E>();
        // stack2用来出队
        public MyStack<E> stack2 = new MyStack<E>();

        // 入队
        public void enqueue(E e){
            stack1.push(e);
            //System.out.println("此时stack1栈顶元素为:" + stack1.top());
        }

        // 出队
        public E dequeue(){
            E e = null;
            if(stack2.size() != 0){
                e = stack2.pop();
            }else if(stack1.size() != 0){
                int length = stack1.size();
                for(int i = 0;i<length;i++){
                    stack2.push(stack1.pop());
                    //System.out.println("此时stack2栈顶元素为:" + stack2.top());
                }
                e = stack2.pop();
            }
            return e;
        }
    }
    /**
     * pop(),push(),max() 复杂度为O(1)
     */
    public static class MyStack<E>{
        public Stack<E> stack,stackMax;
        public MyStack(){
            stack = new Stack<E>();
            stackMax = new Stack<E>();
        }
        // 入栈
        public void push(E e){
            stack.push(e);
            if(stackMax.isEmpty()){
                stackMax.push(e);
            }else if((Integer)stackMax.peek() <= (Integer)e){
                stackMax.push(e);
            }
        }
        // 出栈
        public E pop(){
            E e = stack.pop();
            if(e == stackMax.peek()){
                stackMax.pop();
            }
            return e;
        }
        // 返回最大
        public E max(){
            return stackMax.peek();
        }

        public E peek(){

            return stack.peek();
        }
        public int size(){
            return stack.size();
        }
    }

}





<div class="se-preview-section-delimiter"></div>
  • 测试:有大有小的输入。
  • 时间复杂度:O(n)

栈的进出序列

输入进栈的顺序判断给出的出栈顺序是否正确。

思想:先进栈,然后判断是否和给出的顺序相等。若不相等则继续进栈判断,直到进完;若相等则继续出栈判断,直到出完。


package com.sywyg;

import java.util.Stack;

/**
 * 栈的进出序列
 * @author sywyg
 * @since 2015.7.25
 * 测试:
 */
public class Question5 {

    public static void main(String[] args) {
        Question5 question = new Question5();
        int[] array1 = {1,2,3,4,7};
        int[] array2 = {3,1,2,5,0};
        System.out.println(question.solution(array1, array2));
    }

    // 第一个参数为输入顺序,第二个参数为要判断的输出结果
    public boolean solution(int[] array1,int[] array2){
        // 健壮性判断
        if(array1 == null || array2 == null) return false;
        if(array1.length != array2.length) return false;

        Stack<Integer> stack = new Stack<Integer>();
        int i = 0,j = 0;
        for (; i < array1.length; i++) {
            stack.push(array1[i]);
            while(stack.size() != 0 && stack.peek() == array2[j]) {
                stack.pop();
                j++;
            }
        }
        return j == i?true:false;
    }

}
  • 测试:给出正确的,给出错误的,给出不相等的数组。
  • 时间复杂度:O(n)

版权声明:本文为博主原创文章,未经博主允许不得转载。

栈和队列常见题型(java版)

标签:java   数据结构   算法   

原文地址:http://blog.csdn.net/wangyongge85/article/details/47071481

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!