leetcode探索之旅(隊列)

首先,題目都是出自leetcode的探索里的初級算法的課程。

嘿嘿,有心想學(xué)的請自行前往學(xué)習(xí),光看是沒用的。

隊列:先入先出的數(shù)據(jù)結(jié)構(gòu)

show code

// "static void main" must be defined in a public class.
// java的入口函數(shù) static void main 必須定義在一個public類里

// 隊列實(shí)體
class MyQueue {
    // store elements
    // 存儲隊列內(nèi)容的List
    private List<Integer> data; 
    // a pointer to indicate the start position
    // 指向頭結(jié)點(diǎn)的標(biāo)識
    private int p_start;
    // 隊列實(shí)體的構(gòu)造函數(shù),初始化list和p_start
    public MyQueue() {
        data = new ArrayList<Integer>();
        p_start = 0;
    }
    /** Insert an element into the queue. Return true if the operation is successful. */
    // 類中方法,添加一個元素。添加方法:data.add(),list的add方法向數(shù)組后面添加一個元素
    public boolean enQueue(int x) {
        data.add(x);
        return true;
    };
    /** Delete an element from the queue. Return true if the operation is successful. */
    // 移除一個元素
    // 首先通過isEmpty()方法,如果首元素大于等于list長度,判斷隊列為空
    // 對于隊列,p_start指向隊尾元素時=length-1,當(dāng)最后一個元素出列,p_start=length。>=為一種保險的寫法,我并未想出>的情景
    // 如果隊列非空,p_start自加。
    // 這里有個問題,list并未移除任何元素。以p_start元素判斷隊列是否清空。
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        // 是否可以在這里加入list的移除
        // list.remove(p_start);
        p_start++;
        return true;
    }
    /** Get the front item from the queue. */
    // 獲取隊列的首元素
    public int Front() {
        return data.get(p_start);
    }
    /** Checks whether the queue is empty or not. */
    // 判斷隊列是否為空
    public boolean isEmpty() {
        return p_start >= data.size();
    }     
};

public class Main {
    public static void main(String[] args) {
        // 初始化隊列
        MyQueue q = new MyQueue();
        q.enQueue(5);
        q.enQueue(3);
        // 隊列不為空,輸出首元素,這里應(yīng)該輸出5
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        // 移除5
        q.deQueue();
        // 輸出3
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        // 移除3
        q.deQueue();
        // if(false)
        // p_start = 2
        // data => [5,3]
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
    }
}

由此引出一個更高效的算法——循環(huán)隊列。

// 循環(huán)隊列——使用固定大小的數(shù)組和兩個指針來指示起始位置和結(jié)束位置。目的是重用我們之前提到的被浪費(fèi)的存儲。
// 思路:首先關(guān)鍵點(diǎn)有:
// 1、front和rear指針移動
// 問題:對于指定長度的數(shù)組,當(dāng)我們的下標(biāo)移動的時候必然會遇到下標(biāo)越界,此時理論上講超過數(shù)組范圍的下標(biāo)應(yīng)該移動到0號索引處
// 解決方法:進(jìn)行移動的時候,(front + 1) % queue.length就可獲得正確的下標(biāo),rear同理
// 2、隊空與隊滿的判斷(思路是使用一個實(shí)際存儲長度標(biāo)識 size來參考判斷)
// 因?yàn)槲覀冇胹ize做判斷符號且數(shù)組長度加一以防止下標(biāo)指向空指針
// 所以判空 size == 0;判滿 size == length - 1。
// 3、入隊和出隊操作
// 入隊操作
// 入隊-》判斷隊滿-》入?yún)①x值-》rear后移-》size++
// 出隊操作
// 出隊-》判斷隊空-》front后移-》size--
// 4、返回隊首和隊尾索引
// 隊首很簡單:queue[front] 也可以 front == rear
// 隊尾很奇怪: queue[rear]會在某些情況下失效,舉個栗子:[1,2,3,null],length = 4,front = 0,rear = 3,size = 3,此時的rear-1;[1,2,3,4],length = 3,front = 1,rear = 0,size = 3,此時的rear - 1 = -1,顯然是不行的,此時隊尾應(yīng)該是4,所以使用(rear-1 + length) % length;

class MyCircularQueue {

    private int [] queue;
    private int front;
    private int rear;
    // 記錄實(shí)際隊列長度的數(shù)值
    private int size;
    
    /** Initialize your data structure here. Set the size of the queue to be k. */
    public MyCircularQueue(int k) {
        queue = new int [k + 1];
        front = 0;
        rear = 0;
        size = 0;
    }
    
    /** Insert an element into the cir3W2WXcular queue. Return true if the operation is successful. */
    public boolean enQueue(int value) {
        if (isFull()) {
            return false;
        }
        // 尾元素進(jìn)1,如果超出數(shù)組長度,取mod(求余)
        queue[rear] = value;
        rear = (rear + 1) % queue.length;
        size++;
        return true;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty()) {
            return false;
        }
        // front移動,可不變更
        front = (front + 1) % queue.length;
        size--;
        return true;
    }
    
    /** Get the front item from the queue. */
    public int Front() {
        if (isEmpty()) return -1;
        return queue[front];
    }
    
    /** Get the last item from the queue. */
    public int Rear() {
        if (isEmpty()) return -1;
        return queue[(rear - 1 + queue.length) % queue.length];
    }
    
    /** Checks whether the circular queue is empty or not. */
    public boolean isEmpty() {
        return size == 0;
    }
    
    /** Checks whether the circular queue is full or not. */
    public boolean isFull() {
        return size == queue.length - 1;
    }
}

應(yīng)用:

題目(數(shù)據(jù)流中的移動平均值):
給定一個整數(shù)數(shù)據(jù)流和一個窗口大小,根據(jù)該滑動窗口的大小,計算其所有整數(shù)的移動平均值。

測試用例:
MovingAverage m = new MovingAverage(3); // size = 3
m.next(1) // 1  [1] average = 1/1
m.next(10) // (1 + 10) / 2 [1,10] average = (1+10)/2
m.next(3) // (1 + 10 + 3) / 3 [1,10,3] average = (1+10+3)/2
m.next(5) // (10 + 3 + 5) / 3 [10,3,5] average = (10+3+5)/2

若依次得到測定值(X1,X2,X3,...,Xn)時,按順序取一定個數(shù)所做的全部算術(shù)平均值。 例如(X1+X2+X3)/3,(X2+X3+X4)/3,(X3+X4+X5)/3,(X4+X5+X6)/3...等是移動平均值。

// 剛開始看這道題的時候,我去,我題目都沒看懂。。。
// 后來百度了下移動平均數(shù),然后又找了個題解看了下實(shí)現(xiàn)過程
class MovingAverage {
    // 這是初始化的窗口大小
    int size = 0;
    // 申明一個隊列,使用LinkedList初始化,這是collection中的隊列
    Queue<Integer> queue;
    // 使用sum提前記錄總數(shù),方便取平均數(shù)
    // 注意這里最好定義為double類型,如果是整數(shù)不注意就會精度丟失
    double sum = 0;
    /** Initialize your data structure here. */
    public MovingAverage(int size) {
        this.size = size;
        // 初始化隊列
        queue = new LinkedList<>();
    }
    
    public double next(int val) {
        // 入隊
        queue.offer(val);
        // 求和
        sum += val;
        // 如果超出屏幕
        if (queue.size() > size) {
            Integer head = queue.poll();
            sum -= head;
        }
        // 如果queue小于size ,取queue的長度
        return sum / queue.size();
    }
}

面對過現(xiàn)實(shí)才知道自己多渺小
我畢業(yè)也半年了,一個專升本文憑又因?yàn)樽约旱哪懬印㈦S遇而安的性格錯過了校招,進(jìn)了學(xué)長的一個公司。忙忙碌碌、松松垮垮,經(jīng)歷了一個多月的高強(qiáng)度加班,也經(jīng)歷了松懈的下班玩游戲、看小說、上班劃水。慢慢的自己也感覺到著急,回顧了自己的所學(xué):android半吊子(垃圾碼農(nóng)水準(zhǔn))、java半吊子(碼農(nóng)水準(zhǔn))、vue半吊子(垃圾碼農(nóng)水準(zhǔn))、flutter初學(xué)者(碼農(nóng)都算不上)。畢業(yè)一個月的時候,隔三差五的突然想學(xué)些什么,學(xué)了個把天又置之腦后。我的自制力本來垃圾,又沒一個目標(biāo),渾渾噩噩下來一事無成。我不想這樣直到我失去沖勁、失去追求前進(jìn)的力氣。我現(xiàn)在在這定個目標(biāo):以java工程師的身份進(jìn)到阿里,或許這是個永遠(yuǎn)吃不到的蘿卜,至少我有了明確的前進(jìn)目標(biāo)?!?020-3-12(感覺我心理這個日期已經(jīng)出問題了。。。)

后面如果有實(shí)際使用隊列的情景就加載下方——2020-3-12

我突然發(fā)現(xiàn)我之前的內(nèi)心好像出問題了,我完全不用這么糾結(jié),以進(jìn)某廠為目標(biāo)有什么意思?在寫CRUD的路上,我覺得最求技術(shù)就行,了解感興趣的技術(shù),了解想知道的知識,追求完成作品的樂趣,他不香么?結(jié)果不是必然,探索永無止境?!?020-3-31

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容