Java 使用find min/find max比O(n)更高效的堆栈?
我感兴趣的是创建类似于堆栈的Java数据结构,以尽可能高效地支持以下操作:Java 使用find min/find max比O(n)更高效的堆栈?,java,algorithm,data-structures,stack,big-o,Java,Algorithm,Data Structures,Stack,Big O,我感兴趣的是创建类似于堆栈的Java数据结构,以尽可能高效地支持以下操作: Push,它在堆栈顶部添加一个新元素 Pop,它删除堆栈的顶部元素 Find Max返回(但不删除)堆栈中最大的元素,以及 Find Min,它返回(但不删除)堆栈的最小元素,以及 这种数据结构的最快实现是什么?如何用Java编写它?这是一个经典的数据结构问题。问题背后的直觉如下-最大值和最小值可以改变的唯一方式是将新值推送到堆栈上或从堆栈中弹出新值。考虑到这一点,假设在堆栈中的每个级别上,您都跟踪堆栈中该点或其下的
- Push,它在堆栈顶部添加一个新元素
- Pop,它删除堆栈的顶部元素
- Find Max返回(但不删除)堆栈中最大的元素,以及
- Find Min,它返回(但不删除)堆栈的最小元素,以及
这种数据结构的最快实现是什么?如何用Java编写它?这是一个经典的数据结构问题。问题背后的直觉如下-最大值和最小值可以改变的唯一方式是将新值推送到堆栈上或从堆栈中弹出新值。考虑到这一点,假设在堆栈中的每个级别上,您都跟踪堆栈中该点或其下的最大值和最小值。然后,当您将新元素推送到堆栈上时,您可以通过将刚刚推送到的新元素与当前的最大值和最小值进行比较,轻松地(在O(1)时间内)计算堆栈中任意位置的最大值和最小值。类似地,当您弹出一个元素时,您将在堆栈顶部下一步显示该元素,该元素在堆栈的其余部分中已存储了最大值和最小值 在视觉上,假设我们有一个堆栈,并按顺序添加值2、7、1、8、3和9。我们先推2,然后把2推到堆栈上。由于2现在也是堆栈中的最大值和最小值,我们记录如下:
2 (max 2, min 2)
现在,让我们按7。由于7大于2(当前最大值),因此我们得出以下结论:
7 (max 7, min 2)
2 (max 2, min 2)
请注意,现在我们可以通过查看堆栈顶部,看到7是最大值,2是最小值来读取堆栈的最大值和最小值。如果现在按1,我们得到
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
在这里,我们知道1是最小值,因为我们可以将1与存储在堆栈顶部的缓存最小值(2)进行比较。作为练习,请确保您了解为什么在添加8、3和9后,我们会得到以下结果:
9 (max 9, min 1)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
0 (max 8, min 0)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
现在,如果我们想查询max和min,我们可以在O(1)中通过读取堆栈顶部存储的max和min(分别为9和1)来实现
现在,假设我们从顶部元素弹出。这将产生9,并修改堆栈为
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
现在请注意,这些元素的最大值是8,这正是正确的答案!如果我们再按0,我们会得到:
9 (max 9, min 1)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
0 (max 8, min 0)
3 (max 8, min 1)
8 (max 8, min 1)
1 (max 7, min 1)
7 (max 7, min 2)
2 (max 2, min 2)
如您所见,最大值和最小值的计算是正确的
总的来说,这导致了一个堆栈的实现,它具有O(1)push、pop、find max和find min,这与它得到的一样好。我将把实现留作练习。:-)但是,您可能需要考虑使用标准堆栈实现技术中的一种实现堆栈,例如使用一个或多个对象,每个对象都包含堆栈元素、Min和Max。或者,您可以使用提供的JavaStack
类,尽管IIRC由于该应用程序可能不需要的同步,它有一些开销
有趣的是,一旦您用这些属性构建了一个堆栈,您就可以将其用作构建块来构造和保证时间。您还可以在更复杂的构造中使用它来构建具有这些属性的双端队列
希望这有帮助
<> > >编辑:如果你好奇,我在我的个人站点上有C++的实现,<>强> <强>,前面有<强> <强>。希望这能显示出这在实践中可能是什么样子 虽然答案是对的,但我们可以做得更好。如果堆栈中有很多元素,那么我们就浪费了很多空间。但是,我们可以通过以下方式节省这些无用的空间:
我们可以使用两个堆栈,而不是为每个元素保存最小值(或最大值)。因为最小(或最大)值的更改不会如此频繁,所以只有当新值为当前最小(或最大)值时,我们才会将最小(或最大)值推送到其各自的堆栈中
以下是Java
中的实现:
public class StackWithMinMax extends Stack<Integer> {
private Stack<Integer> minStack;
private Stack<Integer> maxStack;
public StackWithMinMax () {
minStack = new Stack<Integer>();
maxStack = new Stack<Integer>();
}
public void push(int value){
if (value <= min()) { // Note the '=' sign here
minStack.push(value);
}
if (value >= max()) {
maxStack.push(value);
}
super.push(value);
}
public Integer pop() {
int value = super.pop();
if (value == min()) {
minStack.pop();
}
if (value == max()) {
maxStack.pop();
}
return value;
}
public int min() {
if (minStack.isEmpty()) {
return Integer.MAX_VALUE;
} else {
return minStack.peek();
}
}
public int max() {
if (maxStack.isEmpty()) {
return Integer.MIN_VALUE;
} else {
return maxStack.peek();
}
}
}
可能已经来不及回复,但只是为了记录在案。下面是java代码
import java.util.ArrayList;
import java.util.List;
public class MinStack {
List<Node> items;
public void push(int num) {
if (items == null) {
items = new ArrayList<Node>();
}
Node node = new Node(num);
if (items.size() > 0) {
node.min = Math.min(items.get(items.size() - 1).min, num);
node.max = Math.max(items.get(items.size() - 1).max, num);
} else {
node.min = num;
node.max = num;
}
items.add(node);
printStack();
}
public Node pop() {
Node popThis = null;
if (items != null && items.size() > 0) {
popThis = this.items.get(items.size() - 1);
items.remove(items.size() - 1);
}
printStack();
return popThis;
}
public int getMin() {
if (items != null && items.size() > 0) {
int min = this.items.get(items.size() - 1).min;
System.out.println("Minimum Element > " + min);
return min;
}
return -1;
}
public int getMax() {
if (items != null && items.size() > 0) {
int max = this.items.get(items.size() - 1).max;
System.out.println("Maximum Element > " + max);
return max;
}
return -1;
}
public void printStack() {
int i = 0;
for (Node n : items) {
System.out.print(n.data + " > ");
if (i == items.size() - 1) {
System.out.print(" | Min = " + n.min + " |");
System.out.print(" | Max = " + n.max + " |");
}
i++;
}
System.out.println();
}
public static void main(String args[]) {
MinStack stack = new MinStack();
stack.push(10);
stack.push(13);
stack.push(19);
stack.push(3);
stack.push(2);
stack.push(2);
stack.printStack();
stack.pop();
//stack.getMin();
stack.printStack();
}
}
使用Linkedlist:
public class MaxMinStack {
MaxMinLLNode headMin = null;
MaxMinLLNode headMax = null;
MaxMinLLNode tailMin = null;
MaxMinLLNode tailMax = null;
public void push(int data) {
MaxMinLLNode node = new MaxMinLLNode(data, null);
if (headMin == null) {
headMin = node;
tailMin = node;
} else {
if (data < headMin.data) {
tailMin = headMin;
headMin = node;
node.nextNodeReference = tailMin;
}
}
if (headMax == null) {
headMax = node;
tailMax = node;
} else {
if (data > headMax.data) {
tailMax = headMax;
headMax = node;
node.nextNodeReference = tailMax;
}
}
}
public void pop() {
System.out.println("Max Element:" + " " + String.valueOf(headMax.data));
System.out.println("Min Element:" + " " + String.valueOf(headMin.data));
}
public void traverse() {
MaxMinLLNode ptrMin = headMin;
MaxMinLLNode ptrMax = headMax;
System.out.println("Min");
while (ptrMin != null) {
System.out.println(ptrMin.data);
ptrMin = ptrMin.nextNodeReference;
}
System.out.println("Max");
while (ptrMax != null) {
System.out.println(ptrMax.data);
ptrMax = ptrMax.nextNodeReference;
}
}
public static void main(String[] args) {
MaxMinStack m = new MaxMinStack();
m.push(7);
m.push(4);
m.push(5);
m.push(6);
m.push(7);
m.push(8);
m.push(1);
m.push(1);
m.push(7);
m.push(2);
m.push(4);
m.push(2);
m.traverse();
m.pop();
}
}
class MaxMinLLNode {
int data;
MaxMinLLNode nextNodeReference;
MaxMinLLNode(int data, MaxMinLLNode node) {
this.data = data;
this.nextNodeReference = node;
}
}
公共类MaxMinStack{
MaxMinLLNode headMin=null;
MaxMinLLNode headMax=null;
MaxMinLLNode tailMin=null;
MaxMinLLNode tailMax=null;
公共无效推送(整数数据){
MaxMinLLNode节点=新的MaxMinLLNode(数据,null);
如果(headMin==null){
headMin=节点;
tailMin=节点;
}否则{
if(数据<最小水头数据){
tailMin=headMin;
headMin=节点;
node.nextNodeReference=tailMin;
}
}
如果(headMax==null){
headMax=节点;
tailMax=节点;
}否则{
如果(数据>最大水头数据){
tailMax=headMax;
headMax=节点;
node.nextNodeReference=tailMax;
}
}
}
公共空间{
System.out.println(“最大元素:”+“”+String.valueOf(headMax.data));
System.out.println(“最小元素:”+“”+String.valueOf(headMin.data));
}
公共空间遍历(){
MaxMinLLNode ptrMin=headMin;
MaxMinLLNode ptrMax=headMax;
系统输出打印项次(“最小值”);
while(ptrMin!=null){
System.out.println(ptrMin.data);
ptrMin=ptrMin.nextNodeReference;
}
系统输出打印项次(“最大”);
while(ptrMax!=null){
System.out.println(ptrMax.data);
ptrMax=ptrMax.nextNodeReference;
}
}
公共静态void main(字符串[]args){
MaxMinStack m=新的MaxMinStack();
m、 推(7);
m、 p