【数据结构与算法】(四)队列

 

循环队列  循环队列浪费一个储存空间,是因为要区别空队列和满队列,

 

public class CircularQueue {
  // 数组:items,数组大小:n
  private String[] items;
  private int n = 0;
  // head 表示队头下标,tail 表示队尾下标
  private int head = 0;
  private int tail = 0;

  // 申请一个大小为 capacity 的数组
  public CircularQueue(int capacity) {
    items = new String[capacity];
    n = capacity;
  }

  // 入队
  public boolean enqueue(String item) {
    // 队列满了
    if ((tail + 1) % n == head) return false;
    items[tail] = item;
    tail = (tail + 1) % n;
    return true;
  }

  // 出队
  public String dequeue() {
    // 如果 head == tail 表示队列为空
    if (head == tail) return null;
    String ret = items[head];
    head = (head + 1) % n;
    return ret;
  }
}

 

 LeetCode

设计循环双端队列

不知道效率为啥那么低,有时间再优化

class MyCircularDeque {
private: 
    int* items;
    int n;
    int head=0;
    int tail=0;
public:
    
    /** Initialize your data structure here. Set the size of the deque to be k. */
    MyCircularDeque(int k) {
         items=new int[k+1];
         n=k+1;
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    bool insertFront(int value) {
        if ((tail + 1) % n == head) return false;
        
        head = (head+n-1) % n;
        items[head] = value;
        return true;

    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    bool insertLast(int value) {
        if ((tail + 1) % n == head) return false;
        items[tail] = value;
        tail = (tail + 1) % n;
        return true;
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    bool deleteFront() {
        if (head == tail) return false;
        //int ret = items[head];
        head = (head + 1) % n;
        return true;  
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    bool deleteLast() {
      // 如果 head == tail 表示队列为空
        if (head == tail) return false;
        //int ret = items[head];
        tail = (tail+n-1) % n;
        return true;  
    }
    
    /** Get the front item from the deque. */
    int getFront() {
        if(isEmpty()){
            return -1;
        }else {
            return items[head];
        }
    }
    
    /** Get the last item from the deque. */
    int getRear() {
         if(isEmpty()){
            return -1;
        }else {
            return items[(tail+n-1) % n];
        }
    }
    
    /** Checks whether the circular deque is empty or not. */
    bool isEmpty() {
        if (head == tail) return true;
        else return false;
    }
    
    /** Checks whether the circular deque is full or not. */
    bool isFull() {
        if ((tail + 1) % n == head) return true;
        else return false;
    }
};

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * MyCircularDeque* obj = new MyCircularDeque(k);
 * bool param_1 = obj->insertFront(value);
 * bool param_2 = obj->insertLast(value);
 * bool param_3 = obj->deleteFront();
 * bool param_4 = obj->deleteLast();
 * int param_5 = obj->getFront();
 * int param_6 = obj->getRear();
 * bool param_7 = obj->isEmpty();
 * bool param_8 = obj->isFull();
 */

 

2  滑动窗口最大值

使用双端队列

双端队列(deque,全名double-ended queue),是一种具有队列和栈的性质的数据结构。

双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。

  

https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-z/  

我声明了一个变量 deque<int>window,用于存储下标。这个变量有以下 特点:

变量的最前端(也就是 window.front())是此次遍历的最大值的下标
当我们遇到新的数时,将新的数和双项队列的末尾(也就是window.back())比较,如果末尾比新数小,则把末尾扔掉,直到该队列的末尾比新数大或者队列为空的时候才停止,做法有点像使用栈进行括号匹配。
双项队列中的所有值都要在窗口范围内
特点一只是方便我们获取每次窗口滑动一格之后的最大值,我们可以直接通过 window.front() 获得

通过特点二,可以保证队列里的元素是从头到尾降序的,由于队列里只有窗口内的数,所以他们其实就是窗口内第一大,第二大,第三大... 的数。

特点三就是根据题意设置的。但我们实际上只用比较现在的下标和 window.front() 就可以了,想想为什么?

Answer: 因为只要窗口内第一大元素也就是这个 window.front() 在窗口内,那我们可以不用管第二大第三大元素在不在区间内了。因为答案一定是这个第一大元素。如果 window.front() 不在窗口内,则将其弹出,第二个大元素变成第一大元素,第三大元素变成第二大元素以此类推。

代码编写的过程还要时刻检查队列是否为空防止抛出异常。

  vector<int> maxSlidingWindow(vector<int>& nums, int k) {
       
       
        int n=nums.size();
        
        vector<int> result;
        if(n==0) return result;
        deque<int> KWindow;
        for(int i=0;i<k;i++){
  
            while(KWindow.size()>0&&nums[i]>nums[KWindow.back()]){
                KWindow.pop_back();
            }
            
            KWindow.push_back(i);
        }
        result.push_back(nums[KWindow.front()]);
        for(int i=k;i<n;i++){
            while(KWindow.size()>0&&KWindow.front()<i-k+1){
                KWindow.pop_front();
            }
            while(KWindow.size()>0&&nums[i]>nums[KWindow.back()]){
                KWindow.pop_back();
            }
            KWindow.push_back(i);
            result.push_back(nums[KWindow.front()]);
            
       }
       return result;
    }

  



 

转载于:https://www.cnblogs.com/jiwen/p/11380610.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值