题目描述:
假设有这样一个拥有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;
}
}