你們好,我是阿濠,今篇內容跟你們分享的是數據結構之棧,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.
官方定義:棧(stack)是一個後進先出的線性表,它要求只在表尾作進行刪除和插入操做。
棧:後進者先出,先進者後出
,這就是典型的棧結構。java
舉個例子:就像疊盤子
同樣,後來放的盤子老是在上面,拿的時候也是從上面拿,也就是先拿後來放上面的盤子,最後拿最先放的盤子。segmentfault
棧是一種重要的線性結構,棧是線性表的一種形式,在生活中,咱們的瀏覽器,每點擊一次「後退」都是返回最近的一次瀏覽頁面,至關於就是後進先出數組
棧有一些特殊限制:
1.棧元素必須後進先出
2.棧的操做只能在這個線性表的表尾進行
3.對於棧來講,表尾則是棧頂(Top),表頭則是棧底(bottom)瀏覽器
由於棧的本質是線性表,線性表有兩種存儲方式,因此棧也分兩種存儲方式分別爲棧的順序存儲結構、棧的鏈式存儲結構數據結構
棧的插入操做(Push)叫作進棧,也稱爲入棧,對於順序棧的進棧操做只需將新的數據元素存入棧內,而後讓記錄棧內元素個數的變量加1,程序便可再次經過arr[size-1]從新訪問新的棧頂元素。進棧操做示意圖以下:學習
因爲順序棧底層一般會採用數組來保存數據元素,所以可能出現的狀況是:當程序試圖讓一個數據元素進棧時,底層數據已滿,那麼就必須擴充底層數組的長度來容納新進棧的數據元素。spa
棧的刪除操做(Pop)叫作出棧,也稱爲彈棧,對於順序棧的出棧操做而言,須要將棧頂元素彈出棧,程序要作兩件事。3d
對於刪除操做來講,只要讓記錄棧內元素個數的size減1,程序便可經過arr[size-1]訪問到新的棧頂元素。但不要忘記釋放原來棧頂的數組引用,不然會引發內存泄漏。code
棧比普通線性表的功能更弱,棧是一種被限制過的線性表,只能從棧頂插入,刪除數據元素。blog
能夠採用單鏈表來保存棧中全部元素,這種鏈式結構的棧也被稱爲棧鏈。對於棧鏈而言,棧頂元素不斷地改變,程序只要使用一個top引用來記錄當前的棧頂元素便可。
鏈式的進棧操做,只須要作幾件件事:
鏈式的出棧操做,只須要作幾件件事:
從空間利用率的角度說,鏈棧的空間利用率比順序棧的空間利用率要高一些。
java中有封裝好的類,能夠直接調用
push(element)
: 添加一個新元素到棧頂位置.pop()
:移除棧頂的元素,同時返回被移除的元素。peek()
:返回棧頂的元素,不對棧作任何修改(僅僅返回棧頂的元素)。isEmpty()
:若是棧裏沒有任何元素就返回true
,不然返回false
。clear()
:移除棧裏的全部元素。size()
:返回棧裏的元素個數。這個方法和數組的length
屬性很相似。咱們能夠作一個二進制轉換十進制的方式去看看棧的後進先出,從數學的角度來講二進制轉換爲十進制是最低位起去乘以N位的2^(n-1),而後所有加起來
簡單的來講示例二進制:1000 轉換成十進制爲8 why?
代入公式:0*2^(1-1)+0*2^(2-1)+0*2^(3-1)+1*2^(4-1)=0+0+0+8
假設咱們輸入的數字是11001001這樣的二進制數,那麼放入棧就是
若是就會發現top棧頂就是最低位,依次算完發現棧底就是最高位
經過兩個棧
實現的這個功能的
一個棧保存操做數
,另外一個棧保存運算符
,咱們從左到右遍歷表達式
1.當遇到數字時,將其壓入操做數棧;
2.當遇到運算符時,就與運算符棧的棧頂元素進行比較。
若是比運算符棧頂元素的優先級高,就將當前運算符壓入棧;
若是比運算符棧的棧頂元素的優先級低或相同,那麼就從操做數棧的棧頂取2個操做數,而後進行計算,再把計算完成的結果壓入操做數棧,繼續比較。
下面咱們舉個例子:3+5*8-6這個表達式
好比你順序查看了 a,b,c 三個頁面,咱們就依次把 a,b,c 壓入棧,這個時候,兩個棧的數據就是這個樣子:
當你經過瀏覽器的後退按鈕,從頁面 c 後退到頁面 a 以後,咱們就依次把 c 和 b 從棧 X 中彈出,而且依次放入到棧 Y。這個時候,兩個棧的數據就是這個樣子:
這個時候你又想看頁面 b,因而你又點擊前進按鈕回到 b 頁面,咱們就把 b 再從棧 Y 中出棧,放入棧 X 中。此時兩個棧的數據是這個樣子:
這個時候,你經過頁面 b 又跳轉到新的頁面 d 了,頁面 c 就沒法再經過前進、後退按鈕重複查看了,因此須要清空棧 Y。此時兩個棧的數據這個樣子:
最長有效括號
題目描述: 給定一個只包含 '('
和')'
的字符串,找出最長的包含有效括號的子串的長度。
示例 1:
輸入: "(()"
輸出: 2
解釋: 最長有效括號子串爲 "()"
示例 2:
輸入: ")()())"
輸出: 4
解釋: 最長有效括號子串爲 "()()"
// 解法一:棧+暴力 public boolean isValid(String s) { // 判斷任何一個子字符串s是否有效 Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '(') { stack.push('('); } else if (!stack.empty() && stack.peek() == '(') { stack.pop(); } else { return false; } } return stack.empty(); } //* 時間複雜度 O(n^2) 空間複雜度 O(n) * public int longestValidBracketLengthOne(String s) { int maxLength = 0; for (int i = 0; i < s.length(); i++) { for (int j = i + 2; j <= s.length(); j+=2) { if (isValid(s.substring(i, j))) { maxLength = Math.max(maxLength, j - i); } } } return maxLength; }
假設咱們按照思路輸入")())" 初始的時候maxLength=0
1.i=0時,j=2,進入isValid方法的s=")(",這時的stack=0,方法裏的for循環i=0時,無符合要求,直接return false結束j+=2
2.j=4,進入isValid方法的s=")())"這時的stack=0,方法裏的for循環i=0時,無符合要求,直接return false結束i++
3.i=1,j=3,進入isValid方法的s="()",方法裏的for循環i=0時,符合第一個if則push加入棧,stack=1,i++判斷i=1時,不符合第一個if,符合第二個if,由於剛剛加入棧的棧頂='(',這時作了出棧的操做,stack=0,結束方法此時maxLength=3-1=2 結束i++
4.i=2,j=2,進入isValid方法的s="))",不符合for循環,j=4,j=4,進入isValid方法的s=")())",也不符合..
........
此方法一外面for循環作一次,裏面for也要作一次,即作n*n次,因此時間複雜度 O(n^2)
// 解法二:棧 public int longestValidBracketLengthTwo(String s) { if (s == null || s.length() == 0) { return 0; } int maxLength = 0; // 設定返回值 即最長有效括號的長度 int n = s.length(); // 保存須要循環的次數 也就是字符串的最初長度 char[] sArr = s.toCharArray(); // 字符串生成相應的字符數組 Stack<Integer> stack = new Stack<Integer>(); // 建立系統的棧類 存放字符數組中的下標 stack.push(-1); // -1 入棧用於處理邊界條件 for (int i = 0; i < n; i++) { // 循環第i項對應的字符是 ')' // 且 stack.size() > 1 表示棧不爲空 // 且 必須保證棧頂元素(下標 )對應的字符是 '(' if (sArr[i] == ')' && stack.size() > 1 && sArr[stack.peek()] == '(') { stack.pop(); // 對應字符'(' 的棧頂元素(下標 ) 出棧 // 記錄最長長度 由於i是線性往前增長 而棧頂元素(下標 )是線性增減 maxLength = Math.max(maxLength, i - stack.peek()); } else { // 其餘狀況,直接將當前位置入棧 stack.push(i); } } return maxLength; }
假設咱們按照思路輸入")())" 初始的時候maxLength=0
我定義n=輸入的字符串長度也是循環的次數,並生成相對應的char[]字符數組,與系統棧,
給棧定義邊界爲-1,避免對應不上char字符數組
並根據char數組肯定循環次數,從而先找到')'的下標再判斷棧的棧頂是否'(',若是對應的下標不符合要求則將下標加入棧
咱們找到下標0是')',可是目前的棧頂的值對應數組不是'(',因此將下標0放入棧裏,對應的')'稱爲棧頂。
下標1對應的數組是'('不是咱們要找的值
下標2對應的數組是')',符合咱們的要求,目前的棧頂是1,對應的數組是'('符合要求,咱們將目前的棧頂彈出,此時站的個數由3-1=2,且棧頂對應的值就是0,maxLength=2-0
......
由於只須要將字符串變成char數組,而且將數組裏的char判斷符合邏輯問題,因此是 時間複雜度 O(n) 空間複雜度 O(n)