# Leetcode刷題學習筆記 -- Queue
### Introduction
1. 設計一個circular queue
2. 用queue來做BFS。通常是求最小的數量題目。
3. 使用queue來達到輪流的效果
### [622. Design Circular Queue](https://leetcode.com/problems/design-circular-queue/)
設計circular queue。
> 1. 定義每個變數的使用方法。
> head : 指向queue的第一個element。
> tail : 指向queue的最後一個element。
> 2. FIFO從empty -> sz = 1,因為必須滿足(1)。所以head和tail必須指向同一個index,這邊是回到0。
> 3. FIFO從sz = 1 -> empty,因為必須滿足(1)。所以head和tail必須回到-1。
```cpp=
class MyCircularQueue {
vector<int> data;
// 不要混用head和tail的定義,
// head定義: 指向queue的第一個element, 如果queue沒element? 那就指向-1
// tail定義: 指向queue的最後一個element, 如果queue沒element? 那就指向-1
int head, tail, sz;
public:
MyCircularQueue(int k) {
data.resize(k);
head = -1;
tail = -1;
sz = k;
}
bool enQueue(int value) {
if(isFull()) return false;
if(isEmpty()) // 因為fifo為空,所以head = tail = -1,則從idx 0 開始使用
head = 0;
tail = ((tail + 1) % sz);
data[tail] = value;
return true;
}
bool deQueue() {
if(isEmpty()) return false;
if(head == tail) {// 最後一個element, 把head, tail還原成-1
head = -1;
tail = -1;
} else{
head++;
head %= sz;
}
return true;
}
int Front() {
if(isEmpty()) return -1;
return data[head];
}
int Rear() {
if(isEmpty()) return -1;
return data[tail];
}
bool isEmpty() {
return head == -1;
}
bool isFull() {
return head == (tail + 1) % sz;
}
};
```
### [279. Perfect Squares](https://leetcode.com/problems/perfect-squares/)
perfect squares : 是指那些1($1^2$), 4($2^2$), 9($3^2$)這些數。
這題是給你一個n,求出==最少數量==的perfect suqare和。
例如 : n = 12 = 4 + 4 + 4,則回傳3。
```cpp=
int numSquares(int n) {
if(n == 1) return 1;
queue<int> q;
q.push(n); // 目標放進queue
int rtn = 0;
while(!q.empty()) {
for(int loop = q.size(); loop > 0; --loop) {
int cur = q.front(); q.pop();
// 減掉從小到大的perfect square
for(int i = 1; i * i <= cur; ++i) {
int next = cur - i * i;
// 如果達到0就返回
if(next == 0) return rtn + 1;
// 否則就把下一個數字推進去
q.push(next);
}
}
rtn++;
}
return rtn;
}
```
### [752. Open the Lock](https://leetcode.com/problems/open-the-lock/)
給你一個數字鎖從"0000"開始,還有一些deadends數字,如果轉到deadends數字,鎖就動不了了。所以要避開deadends數字,求出==最少的轉動次數==,可以把數字鎖轉到target數字。
```cpp=
int openLock(vector<string>& deadends, string target) {
unordered_set<string> deadlock(deadends.begin(), deadends.end());
// special case
if (deadlock.count("0000")) return -1;
if (target == "0000") return 0;
int res = 0;
// 紀錄訪問過的數字
unordered_set<string> visited{{"0000"}};
queue<string> q{{"0000"}};
while (!q.empty()) {
++res;
for (int k = q.size(); k > 0; --k) {
auto t = q.front(); q.pop();
for (int i = 0; i < t.size(); ++i) {
// 把第i個數字向上向下旋轉
for (int j = -1; j <= 1; ++j) {
if (j == 0) continue;
string str = t;
str[i] = ((t[i] - '0') + 10 + j) % 10 + '0';
if (str == target) return res;
//沒訪問過,也不是deadend數字,就加入queue
if (!visited.count(str) && !deadlock.count(str)) q.push(str);
visited.insert(str);
}
}
}
}
return -1;
}
```
### [281. Zigzag Iterator](https://leetcode.com/problems/zigzag-iterator/)
給你兩個vector<int> v1和v2,設計一個class iterator,可以輪流取v1和v2的值出來。
> 1. 使用queue來達到輪流的效果,取第一個之後,如果還沒取完就排到最後去。達到輪流的效果。
> 2. queue只存每個vector的iterator,這樣就不用複製整個vector進來。
> 3. 以前都習慣用index來存取vector其實用iterator會更好用。因為iterator類似pointer,不需要像index還需要知道本體在哪裡。
```cpp=
class ZigzagIterator {
queue<pair<vector<int>::iterator, vector<int>::iterator>> q;
public:
ZigzagIterator(vector<int>& v1, vector<int>& v2) {
if(!v1.empty()) q.push({v1.begin(), v1.end()});
if(!v2.empty()) q.push({v2.begin(), v2.end()});
}
int next() {
auto [b, e] = q.front(); q.pop();
if(b + 1 != e) q.push({b + 1, e});
return *b;
}
bool hasNext() {
return !q.empty();
}
};
```
###### tags: `leetcode` `刷題`