在C++ STL中,queuedeque的入队和出队操作有明确的规范,但它们的行为有所不同。以下是详细说明:

1. std::queue(队列,FIFO)

  • 入队(push):加到队尾
    queue<int> q;
    q.push(1);  // 队尾:[1]
    q.push(2);  // 队尾:[1,2]
    
  • 出队(pop):从队首移除
    q.pop();    // 移除1,剩下:[2]
    
  • 访问
    • q.front():队首元素
    • q.back():队尾元素

2. std::deque(双端队列)

支持两端操作:

  • 队尾操作
    deque<int> dq;
    dq.push_back(1);  // 队尾:[1]
    dq.push_back(2);  // 队尾:[1,2]
    dq.pop_back();    // 移除2,剩下:[1]
    
  • 队首操作
    dq.push_front(0); // 队首:[0,1]
    dq.pop_front();   // 移除0,剩下:[1]
    
  • 随机访问
    dq[0];  // 访问第0个元素
    

关键区别

操作 queue deque
入队 push(队尾) push_back/push_front
出队 pop(队首) pop_back/pop_front
访问队首 front() front()
访问队尾 back() back()
随机访问 不支持 支持(如dq[2]

为什么滑动窗口用deque

在滑动窗口最小值的算法中,我们需要:

  1. 从队尾移除比当前元素大的值(保持单调性)
  2. 从队首移除过期元素(超出窗口范围)
  3. 从队尾添加新元素

这正是deque支持的高效操作:

deque<int> dq;
// 维护单调递增队列
for (int i = 0; i < n; ++i) {
    // 1. 移除队尾比当前元素大的
    while (!dq.empty() && nums[dq.back()] >= nums[i]) {
        dq.pop_back();
    }
    // 2. 添加当前索引
    dq.push_back(i);
    // 3. 移除过期队首
    while (dq.front() <= i - k) {
        dq.pop_front();
    }
    // 当前窗口最小值是nums[dq.front()]
}

总结

  • queue:严格的FIFO,只能操作队首和队尾

  • deque:灵活的双端操作,适合需要两端修改的场景(如滑动窗口)

    include

    include

    include

    using namespace std;

    int main() {
    vector cars;
    vector requires;
    int num;

      // 读取cars数组
      while (cin >> num) {
          cars.push_back(num);
          if (cin.get() == '\n') break;
      }
      
      // 读取requires数组
      while (cin >> num) {
          requires.push_back(num);
          if (cin.get() == '\n') break;
      }
      
      deque<int> q(requires.begin(), requires.end());
      int K = 0;
      int allocations = 0;
      int remaining = q.size();
      
      for (int car : cars) {
          K += car;
          
          while (!q.empty()) {
              int max_len = 0;
              int current_sum = 0;
              int left = 0;
              int best_left = -1;
              int best_right = -1;
              
              // 滑动窗口找最长子序列
              for (int right = 0; right < q.size(); ++right) {
                  current_sum += q[right];
                  while (current_sum > K && left <= right) {
                      current_sum -= q[left];
                      left++;
                  }
                  if (right - left + 1 > max_len) {
                      max_len = right - left + 1;
                      best_left = left;
                      best_right = right;
                  }
              }
              
              if (max_len == 0) {
                  break;  // 无法分配,退出循环
              }
              
              // 执行分配
              allocations++;
              remaining -= max_len;
              
              // 移除已分配的元素
              deque<int> new_q;
              for (int i = 0; i < q.size(); ++i) {
                  if (i < best_left || i > best_right) {
                      new_q.push_back(q[i]);
                  }
              }
              q = new_q;
              
              // 重置K,因为已分配
              K = 0;
              if (q.empty()) break;  // 需求队列为空,无需继续
          }
      }
      
      cout << allocations << " " << remaining << endl;
      return 0;
    

    }