1. 程式人生 > 其它 >佇列:最近的請求次數 (Leetcode 933 / Leetcode 232 / 劍指09 / Leetcode 225 / Leetcode 862 )

佇列:最近的請求次數 (Leetcode 933 / Leetcode 232 / 劍指09 / Leetcode 225 / Leetcode 862 )

/**
* 暴力解法
* 1.建立陣列,存放所有的請求
* 整型陣列,存放10000個元素
* 2.把當前請求存入陣列
* 記錄最後一次存入的索引,從0開始
* 3.統計距離此次請求前3000毫秒之間的請求次數
* 從最後一次存放位置倒序遍歷
*
* @param t 時長為 t(單位:毫秒) 的請求
* @return 過去3000毫秒內有多少次請求:[t-3000, t]
*/
public int ping(int t) {
// 2.把當前請求存入陣列
int end = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] == 0) { // 細節:陣列元素是0,該位置沒有存過請
求 array[i] = t; end = i; // 記錄最近一次請求存放的索引 break; } } // 3.統計距離此次請求前3000毫秒之間的請求次數 int count = 0; // 計數器 while (array[end] >= t - 3000) { count++; if (--end < 0) { // 防止越界 break; } } return count; }
// 1.建立陣列,存放所有的請求
// int[] array = new int[10000];
int[] array = new int[3002];
// 2.記錄起止索引,從0開始
int start = 0, end = 0;
/** * 優化解法:雙指標 * 1.建立陣列存放請求:int[3002] * 2.額外定義開始指標 * start=0,end=0,記錄起止索引 * 3.存放請求後,更新起止索引 * end++; 從上次的開始索引(start)向後查詢 * 直到新的合法的起始位置 * 4.通過end與start差值計算請求次數 * * @param t 時長為 t(單位:毫秒) 的請求 * @return 過去3000毫秒內有多少次請求:[t-3000, t] */ public int ping(int t) { // 3.存放請求後,更新起止索引 array[end++] = t; // 存放最近一次請求,結束索引加 1 end = end == array.length ? 0 : end; //
越界後,從0開始 // 從start位置開始,正向查詢符合要求的請求次數 while (array[start] < t - 3000) { // 過濾掉所有不符合要求的數 據 start ++; start = start == array.length ? 0 : start; } // 4.通過end與start差值計算請求次數 if (start > end) { // 請求次數超過陣列容量,發生了溢位 return array.length - (start - end); } // 此時,end為最新一次請求 + 1 的索引,start是3000毫秒前的第一次合 法請求索引 return end - start; }
/**
* 最優解:佇列解法
* 1.使用連結串列實現一個佇列
* 定義屬性:隊頭-head、隊尾-tail、長度-size
* 定義方法:新增節點-add(int)、移除節點-poll() 、佇列長度-size()
* 定義內部類:Node,封裝每次入隊的請求資料和指向下一個節點的指標
* 2.每次請求向佇列尾部追加節點
* 3.迴圈檢查隊頭資料是否合法
* 不合法則移除該節點
* 4.返回佇列長度
* @param t
* @return
*/
public int ping(int t) {
// 2.每次請求向佇列尾部追加節點
q.add(t);
// 3.迴圈檢查隊頭資料是否合法
while (q.head.getVal() < t - 3000)
q.poll();
// 4.返回佇列長度
return q.size();
}
/**
* 最優解:佇列解法
* 1.使用連結串列實現一個佇列
* 定義屬性:隊頭-head、隊尾-tail、長度-size
* 定義方法:新增節點-add(int)、移除節點-poll() 、佇列長度-size()
* 定義內部類:Node,封裝每次入隊的請求資料和指向下一個節點的指標
* 2.每次請求向佇列尾部追加節點
* 3.迴圈檢查隊頭資料是否合法
* 不合法則移除該節點
* 4.返回佇列長度
* @param t
* @return
*/
public int ping(int t) {
// 2.每次請求向佇列尾部追加節點
q.add(t);
// 3.迴圈檢查隊頭資料是否合法
while (q.head.getVal() < t - 3000)
q.poll();
// 4.返回佇列長度
return q.size();
}

佇列實現程式碼:

Queue q;
public RecentCounter() {
q = new Queue();
}
class Queue { // 1.使用連結串列實現一個佇列
Node head;
Node tail;
int size = 0;
public Queue() {
}
public void add(int x) { // 向尾部新增一個節點
Node last = tail;
Node newNode = new Node(x);
tail = newNode; // 尾指標指向新節點
if (last == null) { // 第一次新增資料
head = newNode;
tail = newNode;
} else {
last.next = newNode; // 前一個節點指向新節點
}
size++; // 每新增一個節點,佇列長度+1
}
public int poll() { // 從頭部移除一個節點
int headVal = head.val; // 獲取頭節點的資料
Node next = head.next;
head.next = null; // 連結串列第一個節點斷開
head = next; // head指標指向後一個節點
if (next == null) { // 佇列中的最後一個元素
tail = null; // 處理尾指標
}
size--; // 每移出一個節點,佇列長度減1
return headVal;
}
public int size() {
return size;
}
class Node { // 佇列節點:連結串列結構
int val;
Node next;
Node(int x) {
val = x;
}
int getVal() {
return val;
}
}
}

輔助資料結構:佇列。程式碼如下:

class Queue { // 1.使用連結串列實現一個佇列
Node head;
Node tail;
int size = 0;
public Queue() {
}
public void add(int x) {}
public int poll() {}
public int size() {}
class Node { // 佇列節點:連結串列結構
int val;
Node next;
Node(int x) {
val = x;
}
int getVal() {
return val;
}
}
}
輸入:inputs = [[1],[100],[3001],[3002]]
輸出:[1,2,3,3]