LeetCode刷題總結(jié)(1)--棧、隊(duì)列弧满、堆

隊(duì)列:先進(jìn)先出

棧:先進(jìn)后出

堆(優(yōu)先隊(duì)列 ): 邏輯結(jié)構(gòu)上是完全二叉樹(shù)結(jié)構(gòu)婆跑,其中每個(gè)字?jǐn)?shù)的最大值(最小值)節(jié)點(diǎn)是頭節(jié)點(diǎn)。實(shí)際結(jié)構(gòu)常用數(shù)組實(shí)現(xiàn)庭呜。 建立一個(gè)大根堆 時(shí)間復(fù)雜度O(n)


基礎(chǔ)題

1.數(shù)組實(shí)現(xiàn)棧滑进、隊(duì)列 ; 實(shí)現(xiàn)堆排序

class ArrayStack{
    int maxSize;
    int top;
    int []stack;

    public ArrayStack(int maxSize) {
        this.maxSize = maxSize;
        top=-1;
        stack=new int[maxSize];
    }
    //椖蓟眩空
    public boolean isEmpty(){
        return top==-1;
    }
    //棧滿
    public boolean isFull(){
        return top==maxSize-1;
    }
    //入棧
    public void push(int i){
        if(isFull()) {
            System.out.println("棧已滿");
            return;
        }
        stack[++top]=i;
    }
    //出棧
    public int pop(){
        if(isEmpty()){
           throw new RuntimeException("椃龉兀空");
        }
        int val=stack[top];
        top--;
        return val;
    }
    //顯示棧頂元素,不出棧
    public int showPop(){
        if(isEmpty()){
            throw new RuntimeException("椊矗空");
        }
        return stack[top];
    }
    //遍歷
    public void show(){
        if(isEmpty()){
            System.out.println("椡陨螅空");
            return;
        }
        for (int i = 0; i <=top; i++) {
            System.out.printf("stack[%d]=%d   \n",i,stack[i]);
        }

    }

  • 隊(duì)列
class ArrayCircleQueue {
    private int maxSize;
    private int front; //指向隊(duì)頭
    private int rear; //指向隊(duì)尾的后一個(gè)位置,且rear后預(yù)留一個(gè)位置,方便判斷隊(duì)空
    private int []circleArr;

    public ArrayCircleQueue(int maxSize) {
        this.maxSize = maxSize;    //因?yàn)轭A(yù)留一個(gè)位置吉执,實(shí)際上只有maxSize-1個(gè)數(shù)有效
        front=0;
        rear=0;
        circleArr=new int[maxSize];
    }

    public int getMaxSize() {
        return maxSize;
    }

    public int getFront() {
        return front;
    }

    public int getRear() {
        return rear;
    }

    //判斷隊(duì)空
    public boolean isEmpty(){
        return rear==front;
    }
    //判斷隊(duì)滿
    public boolean isFull(){
        return (rear+1)%maxSize==front;
    }
    //入隊(duì)
    public void enqueue(int i){
        if(isFull()){
            System.out.println("隊(duì)列已滿疯淫,不能添加數(shù)據(jù)");
            return;
        }
        circleArr[rear]=i;
        rear=(rear+1)%maxSize;
    }
    //出隊(duì)
    public int dequeue(){
        if(isEmpty()){
            return -1;
        }
        int temp=front;
        front=(front+1)%maxSize;
        return circleArr[temp];
    }
}

//給定數(shù)組  建立大根堆
public static void main(String[] args){
   int[] a={.......};
   int len=a.length;
    //建立大根堆
   for(int i=len/2-1 ; i>=0; i--){
       heapSort(a,i,len);
   }
   for(int i=len-1;i>0;i--){
       int temp=a[i];
       a[i]=a[0];
       a[0]=a[i];
       heapSort(a,0,i);
   }
}
public int[] heapSort(int[] a,int i, int len){
    int temp=a[i];
    for(int j=2*i+1 ; j<len;j=2*j+1){
        if(j+1<len && a[j]<a[j+1]) j++;
        if(a[j]>temp){
            a[i]=a[j];
            i=j;
        }else break;
    }
    a[i]=temp;
}

2.用棧實(shí)現(xiàn)隊(duì)列 ; 用隊(duì)列實(shí)現(xiàn)棧

//棧實(shí)現(xiàn)隊(duì)列
class MyQueue {

Stack<Integer> res = new Stack<>();
public MyQueue() {}
   
public void push(int x) {
    Stack<Integer> temp = new Stack<>();
    while(!res.isEmpty()) temp.push(res.pop());
    temp.push(x);
    while(!temp.isEmpty()) res.push(temp.pop());
}

public int pop() {
    return res.pop();
}

public int peek() {
    return res.peek();
}

public boolean empty() {
    return res.isEmpty();
}

//隊(duì)列實(shí)現(xiàn)棧
同樣準(zhǔn)備兩個(gè)隊(duì)列
class MyStack {
    Queue<Integer> res = new LinkedList<>();
    }   
   
    public void push(int x) {
        Queue<Integer> temp=new LinkedList<>();
        temp.add(x);
        while(res.peek()!=null) temp.add(res.poll());
        while(temp.peek()!=null) res.add(temp.poll());
    }
    
    
    public int pop() {
        return res.poll();
    }
    
    public int top() {
        return res.peek();
    }
    
    public boolean empty() {
        return res.peek()==null;
    }
}

3.實(shí)現(xiàn)一個(gè)特殊的棧戳玫,在實(shí)現(xiàn)棧的基本功能的基礎(chǔ)上,再實(shí)現(xiàn)返回棧中最小元素的操作

//另外定義一個(gè)最小棧  min_stack
class GetMinStack{
    public GetMinStack{
        
    }
    public void push(int x){
        if(min_stack.isEmpty() || x<min_stack.peek() ){
           min_stack.push(x);
         }else min_stack.push(min_stack.peek());
        stack.push(x);
    }
    public int pop(){
        min_stack.pop();
        return stack.pop(); 
    }
    public int getMin(){
        return min_stack.peek();
    }
}

4.驗(yàn)證棧序列

輸入兩個(gè)整數(shù)序列熙掺,第一個(gè)序列表示棧的壓入順序,請(qǐng)判斷第二個(gè)序列是否為該棧的彈出順序咕宿。假設(shè)壓入棧的所有數(shù)字均不相等币绩。例如蜡秽,序列 {1,2,3,4,5} 是某棧的壓棧序列,序列 {4,5,3,2,1} 是該壓棧序列對(duì)應(yīng)的一個(gè)彈出序列缆镣,但 {4,3,5,1,2} 就不可能是該壓棧序列的彈出序列芽突。 ==棧中元素不重復(fù)==

public boolean validateStackSequences(int[] pushed, int[] popped) {
    Stack<Integer> stack = new Stack<>();
    int r = 0;
    for(int i = 0 ; i < pushed.length ; i++){
        stack.push(pushed[i]);
        while(!stack.isEmpty() && stack.peek() == popped[r]){
              stack.pop();
              r++;
          }    
     } 
    return stack.isEmpty();
}

5.有一個(gè)整數(shù)數(shù)組,找出數(shù)組中第K大的數(shù)董瞻。
要找第K大的數(shù)寞蚌,需要維持一個(gè)大小為K的小根堆 , 遍歷結(jié)束結(jié)果就是小根堆的堆頂钠糊。
對(duì)于為什么是小根堆 挟秤,如果遍歷的數(shù)比堆頂小 ,那肯定其他數(shù)都小 抄伍,如果比堆頂大艘刚,就替換堆頂,重新維持小根堆

public class Finder {
    public int findKth(int[] a, int n, int K) {
        // write code here
        int[] heap = new int[K];
        for(int i = 0 ; i < K ; i++) heap[i] = a[i];
        for(int i = K/2 - 1 ; i >= 0 ; i--) heapSort(heap,i);
        for(int i = K ; i < a.length ; i++){
            if(a[i] > heap[0]) heap[0] = a[i];
            heapSort(heap,0);
        }
        return heap[0];
    }
    public void heapSort(int[] heap , int i){
        int temp = heap[i];
        for(int j = 2*i + 1 ; j < heap.length ; j = 2*j + 1){
            if(j+1 < heap.length && heap[j] > heap[j+1]) j++;
            if(heap[j] < temp){
                heap[i] = heap[j];
                i = j;
            }else break;
        }
        heap[i] = temp;
    }
}


進(jìn)階

1.一個(gè)棧一次壓入1,2,3,4,5截珍, 將這個(gè)棧中元素逆序攀甚,即輸出1、2笛臣、3云稚、4、5沈堡,僅用遞歸實(shí)現(xiàn)静陈,不用其他數(shù)據(jù)結(jié)構(gòu)
! 遞歸的本質(zhì)就是棧

public int getStackBottom(Stack<Integer> stack){
    int res=stack.pop();
    if(stack.isEmpty()) return res;
    int last=getStackBottom(stack);
    stack.push(res);
    return last;
}
public void reverse(Stack<Integer> stack){
    if(stack.isEmpty()) return;
    int bot=getStackBottom(stack);
    reverse(stack);
    stack.push(bot);
}

2.更新滑動(dòng)窗口 最大值 最小值問(wèn)題

! 雙端隊(duì)列 隊(duì)列存放數(shù)組元素的下標(biāo)

以更新最大值為例

1.對(duì)于從右側(cè)窗口新進(jìn)入的數(shù)a ,不斷從雙端隊(duì)列的隊(duì)尾釋放小于等于 a 的數(shù)诞丽,直到遇到一個(gè)大于a的數(shù)或者隊(duì)列為空時(shí) 鲸拥, 把 a 從雙端隊(duì)列的隊(duì)尾放入


2.對(duì)于左側(cè)窗口的數(shù)字b ,判斷下標(biāo)是否屬于滑動(dòng)窗口內(nèi) 僧免, 如果不是則彈出


3.這樣就保證隊(duì)頭是該滑動(dòng)窗口的最大值

給定一個(gè)數(shù)組nums ,有一個(gè)大小為k的滑動(dòng)窗口從數(shù)組的最左側(cè)移動(dòng)到數(shù)組的最右側(cè)刑赶。返回滑動(dòng)窗口最大值

    public int[] maxSlidingWindow(int[] nums, int k) {
        LinkedList<Integer> list = new LinkedList<>();
        int[] res = new int[nums.length - k + 1];
        int j = 0;
        for(int i = 0 ; i < nums.length ; i++){
            while(!list.isEmpty() && nums[list.getLast()] < nums[i]){
                list.removeLast();
            }
            list.addLast(i);
            if(list.getFirst() == i-k) list.removeFirst();
            if(i >= k-1) res[j++] = nums[list.getFirst()];
        }
        return res;
    }

3.單調(diào)棧

單調(diào)棧可以用來(lái)找 一個(gè)數(shù)組中 左邊離他最近比他大(小)的數(shù) 和 右邊離他最近比他大(小)的數(shù)

如果找 大數(shù) 就是單調(diào)遞減棧 遍歷數(shù)組 遇到比棧頂小的元素 直接入棧懂衩, 遇到比棧頂大的元素撞叨,棧頂出棧

新棧頂就是左邊離他最近比他大的數(shù) ,要 push的數(shù)就是右邊離他最近比他大的數(shù)

3.a給定 n 個(gè)非負(fù)整數(shù)浊洞,用來(lái)表示柱狀圖中各個(gè)柱子的高度牵敷。每個(gè)柱子彼此相鄰,且寬度為 1 法希。求在該柱狀圖中枷餐,能夠勾勒出來(lái)的矩形的最大面積

LeetCode84.png
// 對(duì)于每個(gè)柱子   往兩邊擴(kuò)散 直到遇到比它小的柱子  就求出以這個(gè)柱子為中心的矩形面積
// 以某個(gè)柱子 i 為中心 ,也就是生成的矩形高為 heights[i]
// 利用單調(diào)遞增棧 求出 每個(gè)柱子 左邊最近比它小的柱子  和 右邊 最近比它小的柱子
// 每次某個(gè)元素出棧的時(shí)候 苫亦,要入棧的元素就是它右邊最近比它小的元素 毛肋, 出棧后的棧頂(新元素還沒(méi)入棧)就是它左邊最近比它小的元素 怨咪,如果出棧后棧為空, 那么就是說(shuō)這個(gè)元素左邊沒(méi)有比它小的元素润匙,可以定義左邊比它小的元素下標(biāo)為-1
// 對(duì)于 相等的元素诗眨,一樣進(jìn)行出棧 ,因?yàn)榧词骨耙粋€(gè)相等的元素提前出棧趁桃,以它為中心生成的最大矩形 一定 被后一個(gè)相等元素生成的矩形囊括
public int getMaxRect(int[] heights){
    Stack<Integer> stack = new Stack<Integer> stack;  //棧中存放的是柱子的下標(biāo)
    int maxSize=0;
    for(int i=0;i<heights.length;i++){
        while(!stack.isEmpty() && heights[i] <= height[stack.peek()]){
            int j = stack.pop()   //記錄中心柱子辽话,即矩形的高
            int l = stack.isEmpty()? -1 : stack.peek();
            int curSize=heights[j] * (i-l-1);
            maxSize = Math.max(maxSize,curSize);
        }
        stack.push(i);
    }
    //如果棧中還有元素   那么棧中元素的右邊沒(méi)有比它小的數(shù)   即右邊下標(biāo)為heights.length
    while(!stack.isEmpty){
        int i=stack.pop();
        int l= stack.isEmpty()? -1 : stack.peek();
        int curSize = heights[i] * (heights.length-l-1);
        maxSize = Math.max(maxSize,curSize);
    }
    return maxSize;
}

3.b 進(jìn)階 最大矩形

LeetCode85.png

思路

  1. 遍歷每一行, 以每一行中的幾個(gè)元素為底 卫病, 求出每一行的最大矩形
  2. 對(duì)于每一行,都可以看成一個(gè)柱狀圖典徘,如上圖中的第三行 對(duì)應(yīng)的柱狀圖 就是 [3,1,3,2,2] 這個(gè)數(shù)組生成的柱狀圖
  3. 每一行的柱狀圖 利用3.a求出最大矩形
public int maximalRectangle(char[][] matrix) {
    int m = matrix.length;
    if(m == 0) return 0;
    int n = matrix[0].length;
    int[] heights = new int[n];
    int maxArea = 0;

    for(int i = 0 ; i < m ; i++ ){
        for(int j = 0 ; j < n ; j++){
            if(matrix[i][j] == '0') heights[j] = 0;   
            else heights[j] += 1;
        }
        maxArea = Math.max(maxArea , getMaxArea(heights) );
    }
    return maxArea;
}
public int getMaxArea(int[] heights){
   //參考上題
}

  1. 給定一個(gè)非空的整數(shù)數(shù)組蟀苛,返回其中出現(xiàn)頻率前 k 高的元素

輸入: nums = [1,1,1,2,2,3], k = 2
輸出: [1,2]

結(jié)合HashMap 和 堆 實(shí)現(xiàn)

class Solution {
    //記錄數(shù)組中元素及其對(duì)應(yīng)出現(xiàn)的次數(shù)
    Map<Integer , Integer> map = new HashMap<>();
    
    public int[] topKFrequent(int[] nums, int k) {    
        int[] heap = new int[k];
        for(int i : nums){
            map.put(i , map.getOrDefault(i,0) + 1);
        }
        Iterator it = map.keySet().iterator();
        int i = 0;
        while(it.hasNext()){
            // 先初始化一個(gè)大小為k的堆,當(dāng)堆中元素個(gè)數(shù)為k時(shí)逮诲,建立小根堆
            if( i < k){
                heap[i] = (Integer)it.next();
                i++;
                if(i == k){
                    for(int j = k/2 -1 ; j >= 0 ; j--){
                        heapSort(heap,j);
                    }
                }
            }else{   //小根堆建好后 帜平,對(duì)于每個(gè)新遍歷的元素與堆頂比較,如果比堆頂大梅鹦,替換
                     //堆頂裆甩,重新維持小根堆
                int key = (Integer)it.next(); 
                if(map.get(key) > map.get(heap[0])) heap[0] = key;
                heapSort(heap , 0);
            }
            
        }
        return heap;
    }
    
    //維持小根堆
    //注意,堆中元素比較是比較它們出現(xiàn)的次數(shù)齐唆,即該元素在map中對(duì)應(yīng)的value
    public void heapSort(int[] heap , int i){
        int temp = heap[i];
        for(int j = 2*i + 1 ; j < heap.length ; j = 2*j + 1){
            if(j+1 < heap.length && map.get(heap[j+1]) < map.get(heap[j])) j++;
            if(map.get(heap[j]) < map.get(temp)){
                heap[i] = heap[j];
                i = j;
            }else break;
        }
        heap[i] = temp;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗤栓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子箍邮,更是在濱河造成了極大的恐慌茉帅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锭弊,死亡現(xiàn)場(chǎng)離奇詭異堪澎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)味滞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門樱蛤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人剑鞍,你說(shuō)我怎么就攤上這事昨凡。” “怎么了攒暇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵土匀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我形用,道長(zhǎng)就轧,這世上最難降的妖魔是什么证杭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮妒御,結(jié)果婚禮上解愤,老公的妹妹穿的比我還像新娘。我一直安慰自己乎莉,他們只是感情好送讲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著惋啃,像睡著了一般哼鬓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上边灭,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天异希,我揣著相機(jī)與錄音,去河邊找鬼绒瘦。 笑死称簿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惰帽。 我是一名探鬼主播憨降,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼该酗!你這毒婦竟也來(lái)了授药?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤垂涯,失蹤者是張志新(化名)和其女友劉穎烁焙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體耕赘,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡骄蝇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了操骡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片九火。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖册招,靈堂內(nèi)的尸體忽然破棺而出岔激,到底是詐尸還是另有隱情,我是刑警寧澤是掰,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布虑鼎,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏炫彩。R本人自食惡果不足惜匾七,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望江兢。 院中可真熱鬧昨忆,春花似錦、人聲如沸杉允。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叔磷。三九已至拢驾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間世澜,已是汗流浹背独旷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留寥裂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓案疲,卻偏偏與公主長(zhǎng)得像封恰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褐啡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354