编程之美3.7:队列中取最大值操作问题

题目描述:
假设有这样一个拥有3个操作的队列:
a. EnQueue(v):将v加入队列中;
b. DeQueue:使队列中的队首元素删除并返回次元素;
c. MaxElement:返回队列中的最大元素

请设计一种数据结构预算法,让MaxElement操作的时间复杂度尽可能低。

解法一:
新建一个队列,然后遍历取得最大值。时间复杂度O(n)。

public class Solution1 {
	public static void EnQueue(int v,Queue<Integer> a) {
		a.add(v);
	}
	public static int DeQueue(Queue<Integer> a) {
		int v = a.poll();
		return v;
	}
	public static int MaxElement(Queue<Integer> a) {
		Queue<Integer> temp = new LinkedList<>();
		int max = a.peek();
		while(a.poll()!=null) {			
			int v = a.poll();
			if(v > max)
				max = v;
			temp.add(v);			
		}
		return max;
	}
	
	public static void main(String[] args) {
		Queue<Integer> a = new LinkedList<>();
		EnQueue(1, a);
		EnQueue(4, a);
		System.out.println(DeQueue(a));
		EnQueue(5, a);
		EnQueue(1, a);
		EnQueue(2, a);
		System.out.println(MaxElement(a));		
	}
}

这里可以做一点改进,在EnQueue(v)中加入比较过程,从而不用重新新建一个队列。
import java.util.LinkedList;
import java.util.Queue;

public class Solution1 {
	public static int EnQueue(int max,int v,Queue<Integer> a) {
		a.add(v);
		if(v > max)
			max = v;
		return max;
	}
	public static int DeQueue(Queue<Integer> a) {
		int v = a.poll();
		return v;
	}
	public static void MaxElement(int max) {
		System.out.println(max);
	}
	
	public static void main(String[] args) {
		Queue<Integer> a = new LinkedList<>();
		int max = 1;
		max = EnQueue(max,1, a);
		max = EnQueue(max,4, a);
		System.out.println(DeQueue(a));
		max = EnQueue(max,5, a);
		max = EnQueue(max,1, a);
		max = EnQueue(max,2, a);
		MaxElement(max);		
	}
}

解法二:
用最大堆来维护队列中的元素。时间复杂度O(1),空间复杂度O(logn)。
这里没有用堆排序,用了类似于LinkedHashMap的实现方式。
import java.util.ArrayList;

public class Solution2 {
	public static void main(String[] args){
		HeapQueue heapQueue = new HeapQueue();
		heapQueue.enQueue(11);
		heapQueue.enQueue(78);
		heapQueue.enQueue(30);
		heapQueue.enQueue(9);
		heapQueue.enQueue(8);
		heapQueue.enQueue(4);
		heapQueue.enQueue(7);
		heapQueue.enQueue(15);
		System.out.println(heapQueue);
		System.out.println(heapQueue.deQueue());
		System.out.println(heapQueue);
		System.out.println(heapQueue.maxValue());
	}
}

class HeapQueue{
	MaxHeap max = new MaxHeap();
	public void enQueue(int x) {
		max.insert(x);
	}
	
	public int deQueue(){	
		int temp = max.head.value;
		max.deleteLast();
		return temp;
	}
	public int maxValue(){
		return max.getMax();
	}
    public String toString() {  
        return max.toString();    
    }  	
}

class MaxHeap {
    private ArrayList<Node> array = new ArrayList<>();  //用来堆排序
    Node tail; //记录链表尾
    Node head; 
    
    //删除最后一个元素   O(2n)
    public void deleteLast() {  
    	Node temp = head;
		head = head.next;
		array.remove(temp);
    }
    
    //获取最大值
    public int getMax(){
    	return array.get(0).value;
    }
    
    //插入一个值     O(2n)
    public void insert(Integer x){         
        Node temp = new Node();
        temp.value = x;
        if(tail == null){
        	tail = temp;
        	head = temp;
        } else {
        	tail.next = temp;
        	tail = temp;
        }
        int i = 0;
        for (; i < array.size(); i++) {
        	if(array.get(i).value < temp.value)
        		break;
        }
        array.add(i, temp);
    } 
    
    //用于显示结果(先显示排序结果,后显示插入顺序,以**为分割)
    public String toString() {  
        StringBuffer sb = new StringBuffer();
        Node temp = head;
        for (int i = 0; i < array.size(); i++)  
            sb.append(array.get(i).value + " ");
        sb.append("**");
        while(temp!= null){
        	sb.append(" " + temp.value);
        	temp = temp.next;
        }
        return new String(sb);    
    } 
    
    //用链表来记录插入顺序,参考LinkedHashMAp
    class Node{
	   Integer value;
	   Node next;
    }
} 

解法三:
维护一个最大值序列保证Max操作的时间复杂度是O(1)。用栈实现队列,栈的Max操作比较容易实现。
public class Solution3 {
		  
	    public static void main(String[] args) {  
	        //定义一个Stack类  
	        Stack s = new Stack(5);  
	        s.push(12);  
	        s.push(3);  
	        s.push(5);  
	        s.push(9);  
	        s.push(6);  
	        s.push(36);  
	        System.out.println(s.Max());  
	        s.Pop();  
	        System.out.println(s.Max());  
	        //定义一个Queue_T类,用Stack实现  
	        Queue_T q = new Queue_T();  
	        q.EnQueue(3);  
	        q.EnQueue(4);  
	        q.EnQueue(2);  
	        System.out.println(q.Max());  
	        q.DeQueue();  
	        q.EnQueue(5);  
	        System.out.println(q.Max());  
	    }  
	  
	    private static class Stack {  
	  
	        private static int maxStackItemIndex;  
	        private static int stackTop;  
	        private static int[] link2NextMaxItenm; //最大值序列 
	        private static int[] stackItem;  
	        private static int maxn;  
	  
	        public Stack(int maxn) {  
	            stackTop = -1;  
	            maxStackItemIndex = -1;  
	            link2NextMaxItenm = new int[maxn];  
	            stackItem = new int[maxn];  
	            this.maxn = maxn;  
	        }  
	  
	        void push(int x) {  
	              
	            if (stackTop >= maxn-1) {} //超出栈的最大存储量
	            else {  
	                stackTop++;  
	                stackItem[stackTop] = x;  
	                if (x > Max()) {  
	                    link2NextMaxItenm[stackTop] = maxStackItemIndex;  
	                    maxStackItemIndex = stackTop;  
	                } else {  
	                    link2NextMaxItenm[stackTop] = -1;  
	                }  
	            }  
	        }  
	        int Pop(){  
	            int ret;  
	            if(stackTop <0){  
	                return -1;  
	            }else{  
	                ret = stackItem[stackTop];  
	                if(stackTop == maxStackItemIndex){  
	                    maxStackItemIndex = link2NextMaxItenm[stackTop];  
	                }  
	                stackTop--;  
	                return ret;  
	            }  
	        }  
	  
	        int Max() {  
	            if (maxStackItemIndex >= 0) {  
	                return stackItem[maxStackItemIndex];  
	            } else {  
	                return -1;  
	            }  
	        }  
	    }	
	}

Queue_T类:
import java.util.Enumeration;

class Queue_T{
	private java.util.Stack<Integer> stackA;
	private java.util.Stack<Integer> stackB;
	private int max_index;
	
	public Queue_T() {
		stackA = new java.util.Stack<Integer>();
		stackB = new java.util.Stack<Integer>();
		max_index = -1;
	}
	void EnQueue(int v) {
		stackB.push(v);
		if(v > max_index) {
			max_index = v;
		}				
	}
	Integer DeQueue() {
		if(stackA.isEmpty()) {
			while(!stackB.isEmpty()) {
				stackA.push(stackB.pop());
			}
		}
		int peek = stackA.pop();
		if(peek == max_index) {
			max_index = LookMax();
		}
		return peek;
	}
	int Max() {
		return max_index;
	}
	int LookMax() {
		int maxA = -1;
		int maxB = -1;
		Enumeration<Integer> itemsA = stackA.elements();
		while(itemsA.hasMoreElements()) {
			if(itemsA.nextElement() > maxA) {
				maxA = itemsA.nextElement();
			}
		}
		if(!stackB.isEmpty()) {
			Enumeration<Integer> itemsB = stackB.elements();
			while(itemsB.hasMoreElements()) {
    			if(itemsB.nextElement() > maxB) {
    				maxB = itemsB.nextElement();
    			}
    		}
		}
		if(maxA > maxB)
			return maxA;
		else
			return maxB;
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值