大廠算法面試之leetcode精講17.棧

大廠算法面試之leetcode精講17.棧

視頻講解(高效學(xué)習(xí)):點擊學(xué)習(xí)

目錄:

1.開篇介紹

2.時間空間復(fù)雜度

3.動態(tài)規(guī)劃

4.貪心

5.二分查找

6.深度優(yōu)先&廣度優(yōu)先

7.雙指針

8.滑動窗口

9.位運算

10.遞歸&分治

11剪枝&回溯

12.堆

13.單調(diào)棧

14.排序算法

15.鏈表

16.set&map

17.棧

18.隊列

19.數(shù)組

20.字符串

21.樹

22.字典樹

23.并查集

24.其他類型題

  • Stack的特點:先進后出(FILO)

  • 使用場景:十進制轉(zhuǎn)2進制 函數(shù)調(diào)用堆棧

  • js里沒有棧匆绣,但是可以用數(shù)組模擬

    42/2 42%2=0
    21/2 21%2=1
    10/2 10%2=0
    5/2   5%2=1
    2/2   2%2=0
    1/2   1%2=1
    stack: [0,1,0,1,0,1]
    res:    1 0 1 0 1 0
    
    fn1(){
      fn2()
    }
    fn2(){
        fn3()
      }
    fn3(){}
    fn1()
    
    stack:[fn1,fn2,fn3]
    
  • 棧的時間復(fù)雜度:入棧和出棧O(1)坟比,查找O(n)
ds_24

20. 有效的括號 (easy)

方法1.棧
ds_25
  • 思路:首先如果字符串能組成有效的括號俺夕,則長度一定是偶數(shù),我們可以遍歷字符串薪伏,遇到左括號則暫存距淫,期待后面有右括號可以和它匹配娱颊,如果遇到右括號則檢查是否能和最晚暫存的做括號匹配。這就和棧這種數(shù)據(jù)結(jié)構(gòu)先進后出的特性相吻合了耽装。所以我們可以準備一個棧存放括號對,遍歷字符串的時候期揪,如果遇到左括號入棧掉奄,遇到右括號則判斷右括號是否能和棧頂元素匹配,在循環(huán)結(jié)束的時候還要判斷棧是否為空凤薛,如果不為空姓建,則不是有效括號匹配的字符串
  • 復(fù)雜度分析:時間復(fù)雜度O(n),空間復(fù)雜度O(n)枉侧,n為字符串的長度

js:

var isValid = function(s) {
    const n = s.length;
    if (n % 2 === 1) {//如果字符串能組成有效的括號引瀑,則長度一定是偶數(shù)
        return false;
    }
    const pairs = new Map([//用棧存儲括號對
        [')', '('],
        [']', '['],
        ['}', '{']
    ]);
    const stk = [];
    for (let ch of s){//循環(huán)字符串
        if (pairs.has(ch)) {
            //遇到右括號則判斷右括號是否能和棧頂元素匹配
            if (!stk.length || stk[stk.length - 1] !== pairs.get(ch)) {
                return false;
            }
            stk.pop();
        } else {
            stk.push(ch);//如果遇到左括號入棧
        }
    };
    return !stk.length;//循環(huán)結(jié)束的時候還要判斷棧是否為空
};

Java:

class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        if (n % 2 == 1) {
            return false;
        }

        Map<Character, Character> pairs = new HashMap<Character, Character>() {{
            put(')', '(');
            put(']', '[');
            put('}', '{');
        }};
        Deque<Character> stack = new LinkedList<Character>();
        for (int i = 0; i < n; i++) {
            char ch = s.charAt(i);
            if (pairs.containsKey(ch)) {
                if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
                    return false;
                }
                stack.pop();
            } else {
                stack.push(ch);
            }
        }
        return stack.isEmpty();
    }
}

232. 用棧實現(xiàn)隊列 (easy)

方法1.棧

動畫過大,點擊查看

  • 思路:這是一道模擬題榨馁,不涉及到具體算法憨栽,考察的就是對棧和隊列的掌握程度。使用棧來模式隊列的行為翼虫,如果僅僅用一個棧屑柔,是一定不行的,所以需要兩個棧一個輸入棧珍剑,一個輸出棧掸宛,這里要注意輸入棧和輸出棧的關(guān)系。在push數(shù)據(jù)的時候招拙,只要數(shù)據(jù)放進輸入棧就好唧瘾,但在pop的時候措译,操作就復(fù)雜一些,輸出棧如果為空饰序,就把進棧數(shù)據(jù)全部導(dǎo)入進來(注意是全部導(dǎo)入)领虹,再從出棧彈出數(shù)據(jù),如果輸出棧不為空求豫,則直接從出棧彈出數(shù)據(jù)就可以了塌衰。最后如果進棧和出棧都為空的話,說明模擬的隊列為空了蝠嘉。
  • 復(fù)雜度分析:push時間復(fù)雜度O(1)最疆,pop時間復(fù)雜度為O(n) ,因為pop的時候蚤告,輸出棧為空努酸,則把輸入棧所有的元素加入輸出棧≌纸桑空間復(fù)雜度O(n)蚊逢,兩個棧空間

js:

var MyQueue = function() {
  //準備兩個棧
   this.stack1 = [];
   this.stack2 = [];
};

MyQueue.prototype.push = function(x) {//push的時候加入輸入棧
   this.stack1.push(x);
};

MyQueue.prototype.pop = function() {
   const size = this.stack2.length;
   if(size) {//push的時候判斷輸出棧是否為空
       return this.stack2.pop();//不為空則輸出棧出棧
   }
   while(this.stack1.length) {//輸出棧為空箫章,則把輸入棧所有的元素加入輸出棧
       this.stack2.push(this.stack1.pop());
   }
   return this.stack2.pop();
};

MyQueue.prototype.peek = function() {
   const x = this.pop();//查看隊頭的元素 復(fù)用pop方法烙荷,然后在讓元素push進輸出棧
   this.stack2.push(x);
   return x;
};

MyQueue.prototype.empty = function() {
   return !this.stack1.length && !this.stack2.length
};

Java:

class MyQueue {

    Stack<Integer> stack1;
    Stack<Integer> stack2;

    public MyQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }
    
    public void push(int x) {
        stack1.push(x);
    }
    
    public int pop() {    
        dumpStack1();
        return stack2.pop();
    }
    
    public int peek() {
        dumpStack1();
        return stack2.peek();
    }
    
    public boolean empty() {
        return stack1.isEmpty() && stack2.isEmpty();
    }

    private void dumpStack1(){
        if (stack2.isEmpty()){
            while (!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
    }
}

155. 最小棧 (easy)

ds_145
  • 思路:定義兩個棧stack和min_stack,stack正常push檬寂,min_stack只會push需要入棧和棧頂中較小的元素终抽。getMin返回min_stack棧頂元素,top返回stack棧頂元素桶至。
  • 復(fù)雜度:所有操作的時間復(fù)雜度是O(1)

js:

var MinStack = function () {
    this.stack = [];
    this.min_stack = [Infinity];
};

//stack正常push昼伴,min_stack只會push需要入棧和棧頂中較小的元素
MinStack.prototype.push = function (x) {
    this.stack.push(x);
    this.min_stack.push(Math.min(this.min_stack[this.min_stack.length - 1], x));
};

//stack正常pop,min_stack正常pop
MinStack.prototype.pop = function () {
    this.stack.pop();
    this.min_stack.pop();
};

//返回stack棧頂元素
MinStack.prototype.top = function () {
    return this.stack[this.stack.length - 1];
};

//返回min_stack棧頂元素
MinStack.prototype.getMin = function () {
    return this.min_stack[this.min_stack.length - 1];
};


java:

class MinStack {
  Deque<Integer> stack;
  Deque<Integer> minStack;

  public MinStack() {
      stack = new LinkedList<Integer>();
      minStack = new LinkedList<Integer>();
      minStack.push(Integer.MAX_VALUE);
  }
  
  public void push(int x) {
      stack.push(x);
      minStack.push(Math.min(minStack.peek(), x));
  }
  
  public void pop() {
      stack.pop();
      minStack.pop();
  }
  
  public int top() {
      return stack.peek();
  }
  
  public int getMin() {
      return minStack.peek();
  }
}

946. 驗證棧序列 (medium)

動畫過大镣屹,點擊查看

  • 思路:用棧模擬出棧入棧的過程圃郊,當(dāng)popped中index指向的位置的元素和stack棧頂?shù)脑匾恢聲r,出棧 并且 index++女蜈,最后判斷stack是否為空
  • 復(fù)雜度:時間復(fù)雜度O(n)持舆,pushed中的元素入棧出棧一次,空間復(fù)雜度O(n)伪窖,棧的大小

js:

const validateStackSequences = (pushed, popped) => {
    const stack = [];//用棧模擬出棧入棧的過程
    let index = 0;
    const len = pushed.length;
    for (let i = 0; i < len; i++) {
        stack.push(pushed[i]);
        //當(dāng)popped中index指向的位置的元素和stack棧頂?shù)脑匾恢聲r逸寓,出棧 并且 index++
        while (popped[index] !== undefined && popped[index] === stack[stack.length - 1]) {
            stack.pop();
            index++;
        }
    }
    return !stack.length;//最后判斷stack是否為空
};

java:

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



445. 兩數(shù)相加 II (medium)

ds_180
  • 思路:將兩個鏈表的節(jié)點都推入棧中,然后不斷出棧覆山,計算每個位置的值和進位竹伸,串連成一個新的鏈表
  • 復(fù)雜度:時間復(fù)雜度O(max(m,n)),m簇宽,n是兩個鏈表的長度勋篓,空間復(fù)雜度O(m+n)

js:

var addTwoNumbers = function(l1, l2) {
    const stack1 = [];
    const stack2 = [];
    while (l1 || l2) {//兩鏈表入棧
        if (l1) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        if (l2) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
    }
    let carry = 0;
    let ansList = null;
    while (stack1.length || stack2.length || carry !== 0) {//不斷出棧
        const s1 = stack1.length ? stack1.pop() : 0;
        const s2 = stack2.length ? stack2.pop() : 0;
        let val = s1 + s2 + carry;
        carry = parseInt(val / 10);//計算進位
        val = val % 10;//計算當(dāng)前節(jié)點的值
        const curNode = new ListNode(val);
        curNode.next = ansList;//向鏈表前插入新節(jié)點
        ansList = curNode;//重新賦值ansList
    }
    return ansList;
};

java:

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new LinkedList<Integer>();
        Deque<Integer> stack2 = new LinkedList<Integer>();
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ansList = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int s1 = stack1.isEmpty() ? 0 : stack1.pop();
            int s2 = stack2.isEmpty() ? 0 : stack2.pop();
            int val = s1 + s2 + carry;
            carry = val / 10;
            val %= 10;
            ListNode curNode = new ListNode(val);
            curNode.next = ansList;
            ansList = curNode;
        }
        return ansList;
    }
}

682. 棒球比賽 (easy)

  • 復(fù)雜度:時間復(fù)雜度O(n)吧享,空間復(fù)雜度O(n)

js:

let calPoints = function(ops) {
    let res = [];
    for(let i = 0; i < ops.length; i++){
        switch(ops[i]){
            case "C":
                res.pop();
                break;
            case "D":
                res.push(+res[res.length - 1] * 2);
                break;
            case "+":
                res.push(+res[res.length - 1] + +res[res.length - 2]);
                break;
            default:
                res.push(+ops[i]);
        }
    }
    return res.reduce((i, j) => i + j);
};

java:

class Solution {
    public int calPoints(String[] ops) {
        Stack<Integer> stack = new Stack();

        for(String op : ops) {
            if (op.equals("+")) {
                int top = stack.pop();
                int newtop = top + stack.peek();
                stack.push(top);
                stack.push(newtop);
            } else if (op.equals("C")) {
                stack.pop();
            } else if (op.equals("D")) {
                stack.push(2 * stack.peek());
            } else {
                stack.push(Integer.valueOf(op));
            }
        }

        int ans = 0;
        for(int score : stack) ans += score;
        return ans;
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市譬嚣,隨后出現(xiàn)的幾起案子耙蔑,更是在濱河造成了極大的恐慌,老刑警劉巖孤荣,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異须揣,居然都是意外死亡盐股,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門耻卡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疯汁,“玉大人,你說我怎么就攤上這事卵酪』衔茫” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵溃卡,是天一觀的道長溢豆。 經(jīng)常有香客問我,道長瘸羡,這世上最難降的妖魔是什么漩仙? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮犹赖,結(jié)果婚禮上队他,老公的妹妹穿的比我還像新娘。我一直安慰自己峻村,他們只是感情好麸折,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粘昨,像睡著了一般垢啼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上雾棺,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天膊夹,我揣著相機與錄音,去河邊找鬼捌浩。 笑死放刨,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的尸饺。 我是一名探鬼主播进统,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼助币,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了螟碎?” 一聲冷哼從身側(cè)響起眉菱,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掉分,沒想到半個月后俭缓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體川慌,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡躏结,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年嘉裤,在試婚紗的時候發(fā)現(xiàn)自己被綠了播急。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挣饥。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡马昨,死狀恐怖把曼,靈堂內(nèi)的尸體忽然破棺而出胡岔,到底是詐尸還是另有隱情椿息,我是刑警寧澤歹袁,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站寝优,受9級特大地震影響条舔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乏矾,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一逞刷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧妻熊,春花似錦夸浅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亿胸,卻和暖如春坯钦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背侈玄。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工婉刀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人序仙。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓突颊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子律秃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容