【问题标题】:Implement stack (push, pop and findmin) in O(1)在 O(1) 中实现堆栈(push、pop 和 findmin)
【发布时间】:2011-05-04 19:25:27
【问题描述】:

我已经看到了这个问题的两个堆栈实现,但我真的很困惑如何获得 O(1) 操作。 考虑以下示例:

S1[3542761986759]
S2[3332221111111]

这里的想法/算法是

  1. 将元素 E 推到 S1 上
  2. 检查 S2 的顶部是否 >= E,如果为真,则在 S2 上插入 E

但是当 getMin 被调用时,我们返回了 S2 的顶部,但是这使得 S2 处于奇怪的状态,因为 S2 包含重复的当前最小元素,所以解决方案是搜索 S2 中的下一个最小元素并返回它。这是 O(n)。

谁能帮我理解解决方案?

【问题讨论】:

  • 它不是那个的副本。它需要恒定的空间。这个有点松散
  • 我真的不知道这是怎么一回事(不记得我是否需要在堆栈中找到 findmin)但是如果你不向 S2 添加重复的最小值怎么办? S2[321]

标签: stack implementation


【解决方案1】:

我在此处发布完整代码以在堆栈中查找 min 和 mx。 时间复杂度为 O(1)

包com.java.util.collection.advance.datastructure;

/** * * @作者vsinha * */ 公共抽象接口堆栈 {

/**
 * Placing a data item on the top of the stack is called pushing it
 * @param element
 * 
 */
public abstract void push(E element);


/**
 * Removing it from the top of the stack is called popping it
 * @return the top element
 */
public abstract E pop();

/**
 * Get it top element from the stack and it 
 * but the item is not removed from the stack, which remains unchanged
 * @return the top element
 */
public abstract E peek();

/**
 * Get the current size of the stack.
 * @return
 */
public abstract int size();


/**
 * Check whether stack is empty of not.
 * @return true if stack is empty, false if stack is not empty
 */
public abstract boolean empty();

}

包com.java.util.collection.advance.datastructure;

@SuppressWarnings("隐藏") 公共抽象接口 MinMaxStack 扩展 Stack {

public abstract int min();

public abstract int max();

}

包com.java.util.collection.advance.datastructure;

导入 java.util.Arrays;

/** * * @作者vsinha * * @参数 */ 公共类 MyStack 实现 Stack {

private E[] elements =null;
private int size = 0;
private int top = -1;
private final static int DEFAULT_INTIAL_CAPACITY = 10;


public MyStack(){
    // If you don't specify the size of stack. By default, Stack size will be 10
    this(DEFAULT_INTIAL_CAPACITY);
}

@SuppressWarnings("unchecked")
public MyStack(int intialCapacity){
    if(intialCapacity <=0){
        throw new IllegalArgumentException("initial capacity can't be negative or zero");
    }
    // Can't create generic type array
    elements =(E[]) new Object[intialCapacity];
}

@Override
public void push(E element) {
    ensureCapacity();
    elements[++top] = element;
    ++size;
}

@Override
public E pop() {
    E element = null;
    if(!empty()) {
        element=elements[top];
        // Nullify the reference
        elements[top] =null;
        --top;
        --size;
    }
    return element;
}

@Override
public E peek() {
    E element = null;
    if(!empty()) {
        element=elements[top];
    }
    return element;
}

@Override
public int size() {
    return size;
}

@Override
public boolean empty() {
    return size == 0;
}

/**
 * Increases the capacity of this <tt>Stack by double of its current length</tt> instance, 
 * if stack is full 
 */
private void ensureCapacity() {
    if(size != elements.length) {
        // Don't do anything. Stack has space.
    } else{
        elements = Arrays.copyOf(elements, size *2);
    }
}

@Override
public String toString() {
    return "MyStack [elements=" + Arrays.toString(elements) + ", size="
            + size + ", top=" + top + "]";
}

}

包com.java.util.collection.advance.datastructure;

/** * 在给定堆栈中找到最小值和最大值的时间复杂度为 O(1)。 * @作者vsinha * */ 公共类 MinMaxStackFinder 扩展 MyStack 实现 MinMaxStack {

private MyStack<Integer> minStack;

private MyStack<Integer> maxStack;

public MinMaxStackFinder (int intialCapacity){
    super(intialCapacity);
    minStack =new MyStack<Integer>();
    maxStack =new MyStack<Integer>();

}
public void push(Integer element) {
    // Current element is lesser or equal than min() value, Push the current element in min stack also.
    if(!minStack.empty()) {
        if(min() >= element) {
            minStack.push(element);
        }
    } else{
        minStack.push(element);
    }
    // Current element is greater or equal than max() value, Push the current element in max stack also.
    if(!maxStack.empty()) {
        if(max() <= element) {
            maxStack.push(element);
        }
    } else{
        maxStack.push(element);
    }
    super.push(element);
}


public Integer pop(){
    Integer curr = super.pop();
    if(curr !=null) {
        if(min() == curr) {
            minStack.pop();
        } 

        if(max() == curr){
            maxStack.pop();
        }
    }
    return curr;
}


@Override
public int min() {
    return minStack.peek();
}

@Override
public int max() {
    return maxStack.peek();
}


@Override
public String toString() {
    return super.toString()+"\nMinMaxStackFinder [minStack=" + minStack + "\n maxStack="
            + maxStack + "]" ;
}

}

// 测试程序

包com.java.util.collection.advance.datastructure;

导入 java.util.Random;

公共类 MinMaxStackFinderApp {

public static void main(String[] args) {
    MinMaxStack<Integer> stack =new MinMaxStackFinder(10);
    Random random =new Random();
    for(int i =0; i< 10; i++){
        stack.push(random.nextInt(100));
    }
    System.out.println(stack);
    System.out.println("MAX :"+stack.max());
    System.out.println("MIN :"+stack.min());

    stack.pop();
    stack.pop();
    stack.pop();
    stack.pop();
    stack.pop();

    System.out.println(stack);
    System.out.println("MAX :"+stack.max());
    System.out.println("MIN :"+stack.min());
}

}

输出:

MyStack [元素=[99, 76, 92, 49, 89, 88, 93, 33, 0, 30], size=10, top=9] MinMaxStackFinder [minStack=MyStack [元素=[99, 76, 49, 33, 0, null, null, null, null, null], size=5, top=4] maxStack=MyStack [元素=[99, null, null, null, null, null, null, null, null, null], size=1, top=0]] 最大:99 最小值:0 MyStack [元素=[99, 76, 92, 49, 89, null, null, null, null, null], size=5, top=4] MinMaxStackFinder [minStack=MyStack [元素=[99, 76, 49, null, null, null, null, null, null, null], size=3, top=2] maxStack=MyStack [元素=[99, null, null, null, null, null, null, null, null, null], size=1, top=0]] 最大:99 最小:49

如果您有任何问题,请告诉我。

谢谢, 维卡什辛哈

【讨论】:

    【解决方案2】:

    使用链表存储当前最小值。添加新数字时,它会查看前一个最小值,如果当前值较低,则将当前最小值更改为当前值。

    例如...假设您有数据:3、6、4、2、7、1。那么这就是列表的样子

    值|最小值

    3|3 -> 6|3 -> 4|3 -> 2|2 -> 7|2 -> 1|1
    

    这将在您推送/弹出项目时跟踪分钟。 当然,您需要有一个根节点和一个指定为“页脚”的节点,以便您可以在 O(1) 中访问末尾。

    或者你可以用它倒退并在前面添加东西并在每次插入时更改根节点......这也可以。应该是这样的:

    1|1 -> 7|2 -> 2|2 -> 4|3 -> 6|3 -> 3|3
    

    那么你就不需要“页脚”节点了。

    这两种方法都会在推送值时跟踪当前最小值。这样,当实际的最小值被推送时,它就会知道 O(1) 中的第二个最小值是多少。

    【讨论】:

      【解决方案3】:

      这是不可能的。否则,您将能够在线性时间内实现比较排序:首先在 O(1) 中推送所有元素,总时间为 O(n),然后 n 次在 O(n) 总时间中得到最小值。

      众所周知,O(n log n) 是比较排序的下界,因此不存在 O(1) push 和 findmin 的解决方案。

      编辑:如 Gabe 所述,将“排序”替换为“比较排序”。

      【讨论】:

      • 更正:comparison 排序不能优于 O(n lg n)。
      • 更具体地说,您可以使用计数排序类型的算法在 O(1) 中实现这一点。
      • 请注意,我的回答并非旨在成为完整的数学证明。或者您是在暗示确实存在这种堆栈的 O(1) 实现?
      • 我不确定答案,我的分析是你不可能得到最大的 O(1) 操作你可以得到 nlg(n)
      • findmin 不会删除最小值,它只会告诉您最小值是多少。 pop 删除最新的元素,而不是最小的,所以这些不足以实现排序。
      猜你喜欢
      • 1970-01-01
      • 2013-10-21
      • 2016-08-16
      • 2019-05-09
      • 2013-04-20
      • 2010-09-30
      • 2021-09-06
      • 2023-04-01
      • 2014-08-12
      相关资源
      最近更新 更多