数据结构与算法-队列之leetcode练习(641,239,622)

设计实现双端循环队列

 

641. Design Circular Deque

 

Design your implementation of the circular double-ended queue (deque).

 

Your implementation should support following operations:

 

MyCircularDeque(k): Constructor, set the size of the deque to be k.

insertFront(): Adds an item at the front of Deque. Return true if the operation is successful.

insertLast(): Adds an item at the rear of Deque. Return true if the operation is successful.

deleteFront(): Deletes an item from the front of Deque. Return true if the operation is successful.

deleteLast(): Deletes an item from the rear of Deque. Return true if the operation is successful.

getFront(): Gets the front item from the Deque. If the deque is empty, return -1.

getRear(): Gets the last item from Deque. If the deque is empty, return -1.

isEmpty(): Checks whether Deque is empty or not. 

isFull(): Checks whether Deque is full or not.

 

 

Example:

 

MyCircularDeque circularDeque = new MycircularDeque(3); // set the size to be 3

circularDeque.insertLast(1);                      // return true

circularDeque.insertLast(2);                      // return true

circularDeque.insertFront(3);                    // return true

circularDeque.insertFront(4);                    // return false, the queue is full

circularDeque.getRear();                         // return 2

circularDeque.isFull();                                  // return true

circularDeque.deleteLast();                       // return true

circularDeque.insertFront(4);                    // return true

circularDeque.getFront();                           // return 4

 

 

Note:

 

All values will be in the range of [0, 1000].

The number of operations will be in the range of [1, 1000].

Please do not use the built-in Deque library.

 

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/design-circular-deque

 

使用链表来实现双端队列

使用链表实现起来较为容易,记录下队头与队尾的指针,对其节点进行添加与删除,就可以很容易的实现双端队列

 

还是看代码吧

/**
 * design implement circular double-ended queue
 *
 *
<p>use linked list
 *
 * @author liujun
 * @version 0.0.1
 * @date 2019/08/25
 */

public class MyCircularDequeLinked {

 
class Node {
   
private int val;

    private
Node next;

    private
Node prev;

    public
Node(int val) {
     
this.val = val;
   
}
  }

 
private final int capacity;

  private int
size;

  private
Node root = new Node(-1);

  private
Node tail = root;

 
/** Initialize your data structure here. Set the size of the deque to be k. */
 
public MyCircularDequeLinked(int k) {
   
this.capacity = k;
   
size = 0;
 
}

 
/** Adds an item at the front of Deque. Return true if the operation is successful. */
 
public boolean insertFront(int value) {

   
if (size < capacity) {

      Node tmpValue =
new Node(value);
     
tmpValue.prev = root;
     
tmpValue.next = root.next;

     
// set next
     
if (root.next != null) {
       
root.next.prev = tmpValue;
     
}
     
     
root.next = tmpValue;

      if
(tail == root) {
       
tail = tmpValue;
     
}

     
size++;
      return true;
   
} else {
     
return false;
   
}
  }

 
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
 
public boolean insertLast(int value) {
   
if (size < capacity) {
      Node tmpValue =
new Node(value);
     
tmpValue.prev = tail;
     
tail.next = tmpValue;
     
tail = tmpValue;

     
size++;
      return true;
   
} else {
     
return false;
   
}
  }

 
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
 
public boolean deleteFront() {
   
if (size > 0) {
      Node front =
root.next;
      if
(front.next != null) {
        front.
next.prev = root;
       
root.next = front.next;
     
} else {
       
root.next = null;
       
tail = root;
     
}

     
size--;
      return true;
   
} else {
     
return false;
   
}
  }

 
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
 
public boolean deleteLast() {
   
if (size > 0) {
      Node lastPrent =
tail.prev;
     
lastPrent.next = tail.next;
     
tail = lastPrent;
     
size--;
      return true;
   
} else {
     
return false;
   
}
  }

 
/** Get the front item from the deque. */
 
public int getFront() {
   
if (size > 0) {
     
return root.next.val;
   
} else {
     
return -1;
   
}
  }

 
/** Get the last item from the deque. */
 
public int getRear() {
   
if (size > 0) {
     
return tail.val;
   
} else {
     
return -1;
   
}
  }

 
public int size() {
   
return size;
 
}

 
/** Checks whether the circular deque is empty or not. */
 
public boolean isEmpty() {
   
return size == 0;
 
}

 
/** Checks whether the circular deque is full or not. */
 
public boolean isFull() {
   
return size == capacity;
 
}
}

 

使用数组来实现双端队列

此使用循环队列来实现,在实现上比链式队列,会复杂很多,队尾的处理与单循环队列无异,但还需要处理队头的指针位置时,在队头插入与删除操作,我画了个图,比较直观点

 

 

 

代码实现

 


/**
 * use array implement circular double-ended queue
 *
 * @author liujun
 * @version 0.0.1
 * @date 2019/08/26
 */

public class MyCircularDequeArray {

 
private final int capacity;

  private final int
[] array;

  private int
size;

  private int
head;

  private int
tail;

 
/** Initialize your data structure here. Set the size of the deque to be k. */
 
public MyCircularDequeArray(int k) {
   
this.array = new int[k + 1];
    this
.capacity = k + 1;
   
size = 0;
 
}

 
/** Adds an item at the front of Deque. Return true if the operation is successful. */
 
public boolean insertFront(int value) {
   
// when queue is full
   
if ((tail + 1) % capacity == head) {
     
return false;
   
} else {

     
head = (head + capacity - 1) % capacity;
     
array[head] = value;
     
size++;

      return true;
   
}
  }

 
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
 
public boolean insertLast(int value) {
   
// when queue is full
   
if ((tail + 1) % capacity == head) {
     
return false;
   
} else {
     
array[tail] = value;
     
tail = (tail + 1) % capacity;
     
size++;
      return true;
   
}
  }

 
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
 
public boolean deleteFront() {
   
if (tail == head) {
     
return false;
   
} else {
     
head = (head + 1) % capacity;
     
size--;
      return true;
   
}
  }

 
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
 
public boolean deleteLast() {
   
if (tail == head) {
     
return false;
   
} else {
     
tail = (tail - 1 + capacity) % capacity;
     
size--;
      return true;
   
}
  }

 
/** Get the front item from the deque. */
 
public int getFront() {
   
if (tail == head) {
     
return -1;
   
} else {
     
return array[head];
   
}
  }

 
/** Get the last item from the deque. */
 
public int getRear() {
   
if (tail == head) {
     
return -1;
   
} else {
     
int readIndex = (tail - 1 + capacity) % capacity;
      return
array[readIndex];
   
}
  }

 
public int size() {
   
return size;
 
}

 
/** Checks whether the circular deque is empty or not. */
 
public boolean isEmpty() {
   
return size == 0;
 
}

 
/** Checks whether the circular deque is full or not. */
 
public boolean isFull() {
   
return (tail + 1) % capacity == head;
 
}
}

 

 

求滑动窗口的最大值

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

 

Example:

 

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3

Output: [3,3,5,5,6,7]

Explanation:

 

Window position                Max

---------------               -----

[1  3  -1] -3  5  3  6  7       3

 1 [3  -1  -3] 5  3  6  7       3

 1  3 [-1  -3  5] 3  6  7       5

 1  3  -1 [-3  5  3] 6  7       5

 1  3  -1  -3 [5  3  6] 7       6

 1  3  -1  -3  5 [3  6  7]      7

Note:

You may assume k is always valid, 1 ≤ k ≤ input array's size for non-empty array.

 

Follow up:

Could you solve it in linear time?

 

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/sliding-window-maximum

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

使用双端队实现

此实现就是在窗口中求最大值。可用使用一个双端队列实现,双端队列的大小为窗口的大小,每放入一个元素,从队头移除一个元素,又向队尾追加一个元素。在队列中求中最大值。还是来画个图,更为直观点吧!

使用java原生的LinkedList实现


/**
 *
使用双端队列来解决此滑动窗口的问题
 
*
 * @author liujun
 * @version 0.0.1
 * @date 2018/11/17
 */

public class SolutionDequeue {

 
/**
   *
求滑动窗口的最大值
  
*
   *
<p>由于需要对每个窗口做求最大数,时间复杂度为O(N*K)
   *
   * @param
nums 输入数据集
  
* @param k 窗口大小
  
* @return 窗口内最大值
  
*/
 
public int[] maxSlidingWindow(int[] nums, int k) {

   
if (null == nums) {
     
return null;
   
}

   
if (nums.length == 0) {
     
return nums;
   
}

   
if (k > nums.length) {
     
return null;
   
}

   
int[] result = new int[nums.length - k + 1];

    int
readIndex = 0;

   
// 读取首次记录
   
LinkedList<Integer> dequeue = new LinkedList<>();

    for
(int i = 0; i < nums.length; i++) {
     
// 移除比当前元素小的对象
     
while (!dequeue.isEmpty() && nums[dequeue.peekLast()] <= nums[i]) {
        dequeue.pollLast()
;
     
}
      dequeue.add(i)
;

     
// 进行窗口滑动的调整
     
while (dequeue.peekFirst() < i - k + 1) {
        dequeue.pollFirst()
;
     
}

     
if (i + 1 >= k) {
        result[readIndex++] = nums[dequeue.peekFirst()]
;
     
}
    }

   
return result;
 
}
}

 

 

 

使用循环双端队实现

 

使用循环队列来替代linkedList,解题思路与前面队列一致

 

 


/**
 *
使用双端循环队列来解决求窗口最大值
 
*
 * @author liujun
 * @version 0.0.1
 * @date 2019/08/27
 */

public class SolutionCycleArrayQueue {

 
/**
   *
求滑动窗口的最大值
  
*
   * @param
nums 输入数据集
  
* @param k 窗口大小
  
* @return 窗口内最大值
  
*/
 
public int[] maxSlidingWindow(int[] nums, int k) {
   
if (null == nums || nums.length == 0 || nums.length <= k) {
     
return nums;
   
}
   
int[] reslut = new int[nums.length - k + 1];

   
//使用一个循环队列
   
int[] queue = new int[k];

   
// 加载值
   
for (int i = 0; i < k; i++) {
      queue[i] = nums[i]
;
   
}

   
// 求最大值
   
int readIndex = 0;
   
reslut[readIndex] = maxValue(queue);
   
readIndex++;

    int
addnextPosition = 0;

    for
(int i = k; i < nums.length; i++) {
      queue[addnextPosition] = Integer.
MIN_VALUE;
     
queue[addnextPosition] = nums[i];
     
reslut[readIndex++] = maxValue(queue);
     
addnextPosition = (addnextPosition + 1) % k;
   
}

   
return reslut;
 
}

 
private int maxValue(int[] value) {
   
int maxValue = value[0];
    for
(int i = 1; i < value.length; i++) {
     
if (maxValue < value[i]) {
        maxValue = value[i]
;
     
}
    }
   
return maxValue;
 
}
}

 

 

 

 

设计实现一个循环双端队列

Design your implementation of the circular queue.
The circular queue is a linear data structure in which the operations are performed based on FIFO (First In First Out)
principle and the last position is connected back to the first position to make a circle.
It is also called "Ring Buffer".

One of the benefits of the circular queue is that we can make use of the spaces in front of the queue. In a normal queue,
once the queue becomes full, we cannot insert the next element even if there is a space in front of the queue.
But using the circular queue, we can use the space to store new values.

Your implementation should support following operations:

MyCircularQueue(k): Constructor, set the size of the queue to be k.
Front: Get the front item from the queue. If the queue is empty, return -1.
Rear: Get the last item from the queue. If the queue is empty, return -1.
enQueue(value): Insert an element into the circular queue. Return true if the operation is successful.
deQueue(): Delete an element from the circular queue. Return true if the operation is successful.
isEmpty(): Checks whether the circular queue is empty or not.
isFull(): Checks whether the circular queue is full or not.
 

Example:

MyCircularQueue circularQueue = new MyCircularQueue(3); // set the size to be 3
circularQueue.enQueue(1);  // return true
circularQueue.enQueue(2);  // return true
circularQueue.enQueue(3);  // return true
circularQueue.enQueue(4);  // return false, the queue is full
circularQueue.Rear();  // return 3
circularQueue.isFull();  // return true
circularQueue.deQueue();  // return true
circularQueue.enQueue(4);  // return true
circularQueue.Rear();  // return 4
 
Note:

All values will be in the range of [0, 1000].
The number of operations will be in the range of [1, 1000].
Please do not use the built-in Queue library.

 

 

我的实现

特别需要注意判断空

 


/**
 * @author liujun
 * @version 0.0.1
 * @date 2019/08/29
 */

public class MyCircularQueue {

 
private final int[] array;

  private final int
capacity;

  private int
head;

  private int
tail;

  private int
size;

 
/** Initialize your data structure here. Set the size of the queue to be k. */
 
public MyCircularQueue(int k) {
   
this.array = new int[k + 1];
    this
.capacity = k + 1;
 
}

 
/** Insert an element into the circular queue. Return true if the operation is successful. */
 
public boolean enQueue(int value) {
   
if ((tail + 1) % capacity == head) {
     
return false;
   
}
   
array[tail] = value;
    
tail = (tail + 1) % capacity;
   
size++;
    return true;
 
}

 
/** Delete an element from the circular queue. Return true if the operation is successful. */
 
public boolean deQueue() {
   
if (tail == head) {
     
return false;
   
}
   
head = (head + 1) % capacity;
   
size--;
    return true;
 
}

 
/** Get the front item from the queue. */
 
public int Front() {
   
if (this.isEmpty()) {
     
return -1;
   
}

   
return this.array[head];
 
}

 
/** Get the last item from the queue. */
 
public int Rear() {
   
if (this.isEmpty()) {
     
return -1;
   
}

   
int tailiIndex = (tail - 1 + capacity) % capacity;
    return
array[tailiIndex];
 
}

 
/** Checks whether the circular queue is empty or not. */
 
public boolean isEmpty() {
   
return tail == head;
 
}

 
/** Checks whether the circular queue is full or not. */
 
public boolean isFull() {
   
return (tail + 1) % capacity == head;
 
}

 
public int size() {
   
return size;
 
}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值