【问题标题】:Get max element in a Queue | Java获取队列中的最大元素 |爪哇
【发布时间】:2016-11-29 22:43:05
【问题描述】:

是否有另一种方法来获取队列中的最大元素(Java)? (请提供替代方法)

import java.util.*;

public class MaxQueueElement<E extends Comparable<E>> {

    public MaxQueueElement(Queue<E> queue){
        E max= queue.peek();   // initialize max with head of queue

        for(E e : queue){
            if(e.compareTo(max) > 0){
                max = e;
            }
        }

    System.out.println(max);

 }
}

【问题讨论】:

  • Collections.max(queue) 似乎更容易。
  • 不,我说的是另一种算法
  • 我在软件工程中看到的一条常见规则是 KISS:保持简短和简单。您的解决方案有效。为什么不必要地使事情复杂化?
  • 好吧,我们也不是。最好的办法是问你的讲师。
  • 有其他方法吗?是的,有无数种选择。有没有更好的办法?取决于您对更好的定义(例如,代码可能更通用)。但是这种方法具有最佳的大复杂度。

标签: java generics queue


【解决方案1】:

通过在单独的双端队列 (Deque) 中维护最大值的候选者,可以在平摊的 O(1) 时间内实现队列上的 get-max 操作。

  • 在入队(或offer)操作时,我们检查Deque 后面是否有任何元素的值小于被入队的元素。这些值可以简单地删除——因为这些值永远不会是未来的最大值。
  • 在出队(或poll)操作中,我们检查Deque 中的第一个元素是否等于常规队列中的第一个元素,如果是,也将其删除。
  • max 元素只是Deque 的第一个元素。

所有操作都具有平均 O(1) 时间复杂度。

这是一个 Java 实现:

public class QueueWithMax<T extends Comparable<T>> {
    Queue<T> queue;
    Deque<T> cMax; // candidates for Max value

    public QueueWithMax() {
        queue = new LinkedList<>();
        cMax = new LinkedList<>();
    }

    public void offer(T element) {
        queue.offer(element);
        while (!cMax.isEmpty() && element.compareTo(cMax.peekLast()) > 0) {
            cMax.pollLast();
        }
        cMax.offerLast(element);
    }

    public T poll() {
        if (cMax.peekFirst().equals(queue.peek()))
            cMax.pollFirst();
        return queue.poll();
    }

    public T getMax() {
        return cMax.peekFirst();
    }
}

【讨论】:

  • 这太棒了!我以前从未听说过这样的数据结构。是你自己发明的吗?
  • @ciamej 这其实是解决leetcode.com/problems/sliding-window-maximum等问题的常用策略。但是,我在 Aziz 等人中找到了正式的定义。编程面试的要素。
【解决方案2】:

访问Queue 中所有元素的唯一方法是使用iterator() 方法 - 您不能(通常)通过索引访问元素(如某些实现可能,但Queue 没有t 天生)。

因此,您所能做的就是一次迭代一个元素,存储当前的最大元素。这正是你在这里所做的。

您的算法没有任何问题 - 但您实现它的方式可以改进:

  • 不要在类的构造函数中这样做——你不需要构造任何东西的新实例,因为最大值已经存在。以(静态)方法执行。
  • 不要打印结果——这对人和野兽都没有用。将其返回给调用者。
  • 处理队列为空且可能包含空值的情况。 (请参阅Collections.max 的 Javadoc 以获得想法)

【讨论】:

    【解决方案3】:

    您可以使用 Java 8 的流对队列进行排序,它在内部使用相同的算法但会产生更少的噪声代码,例如:

    public void MaxQueueElement(Queue<E> queue){
        Optional<E> max = queue.stream()
            .max(Comparable::compareTo);
    
        if(max.isPresent()){
            System.out.println(max.get());
        }
    }
    

    另一种方法是将PriorityQueue 与比较器一起使用并从中获取第一个元素。例如:

    public void MaxQueueElement2(Queue<E> queue){
        PriorityQueue<E> pQueue = new PriorityQueue<>((E e1, E e2)->e1.compareTo(e2));
        pQueue.addAll(queue);
        System.out.println(pQueue.peek());
    
    }
    

    【讨论】:

    • 更好的Comparator.naturalOrder()max.ifPresent(System.out::println)
    【解决方案4】:

    除非队列不是像PriorityQueue 这样的特殊排序队列,否则从算法的角度来看没有更好的方法。由于队列没有任何固有的排序属性,因此您必须先检查队列中的所有元素,然后才能找到。

    代码或多或少没问题。如果队列包含null,它将失败。通常情况并非如此,但可能会发生。
    MaxQueueElement 构造有点奇怪。

    【讨论】:

      【解决方案5】:

      我正在上计算机科学课,我们不允许使用 for each 循环。我不确定它是否和你一样。请注意,for each 循环类型违背了队列的目的,因为您只想处理队列的前端和后端。特别是在我的课程中,我们还希望队列在传递到方法之前处于其原始状态,而不使用额外的辅助数据结构。以下是我在测试中的做法:

      public E findMaxQueueElement(Queue<e> queue) { //my test would ask me to return the max value
          E max = queue.remove();
          queue.add(max); //add it back to the end
          for(int i=0; i<queue.size()-1; i++) {
              E current = queue.remove();
              if (current.compareTo(max) > 0) {
                  max = current;
              }
              queue.add(current);
          }
          return max;
      }
      

      根据我提供的限制,这应该可行。我希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        我想你也可以利用 Collections.max(queue) 在队列的情况下

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-08
          • 1970-01-01
          • 2013-09-17
          • 1970-01-01
          • 2017-08-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-02
          相关资源
          最近更新 更多