1. 程式人生 > >java判斷有效的括號序列

java判斷有效的括號序列

需求:

給定一個字串所表示的括號序列,包含以下字元: '(', ')', '{', '}','[' and']', 判定是否是有效的括號序列。

分析:

1、對於有效的括號序列,滿足下列特點:

    1)有效的括號序列長度是不為0的偶數,所以字串長度為0或者奇數時就返回false

    2)如果第一個字元是右括號或者最後一個字元是左括號,那麼不是有效括號序列,會返回false

    上述1)和2)可以直接判斷不是有效括號序列,這樣就減少了記憶體以及時間開銷。比如對於"{(){"序列,如果不進行2)的判斷,可能需要開闢堆疊空間,判斷到最後才得出false的結論,但是如果一開始就判斷開頭和結尾是否滿足有效括號序列的條件,就可以不開闢堆疊空間,進而減少記憶體開銷,提高程式碼效率。

2、資料結構選用堆疊

    堆疊是一種LIFO(後進先出)的資料結構。遍歷字串,將左括號推入堆疊,對於右括號,判斷棧頂元素與其是否匹配,如果不匹配就不有效,否則彈出棧頂元素,說明該層的括號已經判斷完畢,繼續遍歷字串進行判斷。遍歷之後,需要判斷堆疊是否為空,如果不是空的,說明左括號多於右括號,不有效,返回false,否則返回true。

3、java中的堆疊實現

   1) Stack類

    JDK1.0提供了Stack類,即堆疊類,有如下方法

    boolean empty()//判斷堆疊是否為空
    E push(E e)//將元素e推入棧頂
    E peek()//獲取棧頂元素
    E pop()//彈出棧頂元素
    int search(Object obj)//此方法返回距堆疊頂部最近的出現位置到堆疊頂部的距離;堆疊中最頂部項的距離為 1。使用equals 方法比較o 與堆疊中的項。

    2)Deque介面

    Deque(Double ended queue雙端佇列)介面實現了提供LIFO堆疊操作的一系列更完整和更一致的set,應該優先使用Deque的子類,而非Stack,比如:

    Deque<Integer> deq = new ArrayDeque<Integer>();

    在將雙端佇列用作佇列時,將得到 FIFO(先進先出)行為。將元素新增到雙端佇列的末尾,從雙端佇列的開頭移除元素。從Queue介面繼承的方法完全等效於Deque方法;雙端佇列也可用作 LIFO(後進先出)堆疊。應優先使用此介面而不是遺留Stack 類。在將雙端佇列用作堆疊時,元素被推入雙端佇列的開頭並從雙端佇列開頭彈出。堆疊方法完全等效於Deque

方法。

    ArrayDeque是Deque的子類,既可以實現堆疊,又可以實現佇列。ArrayDeque用作堆疊時,效率比Stack高,用作佇列時,效率比LinkedList高,所以一般使用ArrayDeque來實現堆疊和佇列的資料結構。

    3)Deque介面方法摘要

    a)判斷

    boolean isEmpty()//判斷是否是空的

    b)新增元素

    void push(E e)//將元素e推入表示的堆疊棧頂
    boolean offer(E e)//在雙端佇列尾部新增元素等價於offerLast()
    boolean offerFirst(E e)//在雙端佇列頭部新增元素
    boolean offerLast(E e)//在雙端佇列尾部新增元素
    使用offer替換add方法

    c)獲取元素

    E peek()//獲取雙端佇列頭部元素,等價於peekFirst()
    E peekFirst()//獲取雙端佇列頭部元素
    E peekLast()//獲取雙端佇列尾部元素
    使用peek替換get方法

    d)刪除元素

    E pop()//彈出棧頂元素
    E poll()//獲取並移除佇列頭部元素,等價於pollFirst()
    E pollFirst()
    E pollLast()//獲取並移除雙端佇列尾部元素
    使用poll代替remove

    e)獲取元素個數

    int size()

    4)ArrayDeque

    用作堆疊:push(E e)                    pop()    peek()/peekFirst()
    用作佇列:offer(E e)/offerLast(E e)    poll()   peek()

步驟:

1、判斷分析中的1)和2)條件,提高程式碼效率。如果返回false,程式結束,否則進行步驟2

2、建立堆疊,遍歷字串,如果是左括號,則推入堆疊中,如果是右括號,判斷堆疊是否是空的,如果是空的返回false,否則看棧頂元素是否和該右括號匹配,如果不匹配返回fasle,如果匹配就將棧頂彈出,繼續遍歷字串

3、字串遍歷結束,判斷堆疊是否是空的,如果不是空的,說明左括號數量大於右括號,不是有效括號序列,返回false,否則返回true

程式碼:

public class Solution {
    /*
     * @param s: A string
     * @return: whether the string is a valid parentheses
     */
    public boolean isValidParentheses(String s) {
        // write your code here
        //如果字串為null或者長度是奇數或者0,那麼就不是有效括號,就返回false
        //如果字串的頭部是右括號或者尾部是左括號,返回fasle
        int len = s.length();
        if(s == null || len == 0 || len % 2 != 0)
        {
            return false;
        }
        
        char start = s.charAt(0);
        char end = s.charAt(len - 1);
        if(start == '}' || start == ')' || start == ']')
        {
            return false;
        }
        if(end == '{' || end == '(' || end == '[')
        {
            return false;
        }
        
        //建立堆疊
        Deque<Character> stack = new ArrayDeque<Character>();
        
        //遍歷字串,如果是左括號就新增到堆疊中,如果是右括號,看是否和棧頂元素匹配,匹配就pop棧頂元素,不匹配就返回false,如果遍歷到最後一個元素,並且和棧頂元素匹配即可返回true,否則fasle
        for(int i = 0; i < len; i++)
        {
            char ch = s.charAt(i);
            
            //如果是左括號就直接新增進堆疊
            if(ch == '{' || ch == '(' || ch == '[')
            {
                stack.push(ch);
            }
            //如果是右括號,進行匹配判斷
            else if(ch == '}' || ch ==')' || ch ==']')
            {
                if(stack.isEmpty())
                {
                    return false;
                }
                else
                {
                    char peek = stack.peek();
                    if(isMatch(peek, ch))
                    {
                        stack.pop();
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }
        
        //判斷堆疊是否是空的,如果是空的,就是
        if(stack.isEmpty())
        {
            return true;
        }
        
        return false;
    }
    
    //判斷是否是匹配的括號對
    public boolean isMatch(char c1, char c2)
    {
        return (c1 == '{' && c2 == '}' || c1 == '(' && c2 == ')' || c1 == '[' && c2 == ']')? true: false;
    }

}