【經典問題】括號匹配問題

前言

括號匹配問題算是棧應用中比較經典的問題了,在數據結構的書中還有各種考試中會出現。最近刷題的時候也遇到了,就想寫一篇文章整理一下。

例題

題目來自Leetcode中國
給定一個只包括 (){}[] 的字符串,判斷字符串是否有效。
有效字符串需滿足:
1、左括號必須用相同類型的右括號閉合。
2、左括號必須以正確的順序閉合。
注意空字符串可被認爲是有效字符串。
示例 1:

輸入: “()”
輸出: true

示例 2:

輸入: “()[]{}”
輸出: true

示例 3:

輸入: “(]”
輸出: false

示例 4:

輸入: “([)]”
輸出: false

示例 5:

輸入: “{[]}”
輸出: true

算法思想

S1:遍歷輸入的括號序列,如果是左括號,進入S2,如果是右括號,進入S3
S2:如果當前遍歷到左括號,則入棧
S3:如果當前遍歷到右括號,則出棧一個元素,看其是否與當前的右括號組成一對,如果不是,則匹配失敗。或者在出棧過程中發生異常(從空棧中出棧),也匹配失敗
S4:若能順利遍歷完成,檢查棧中是否還有剩餘元素,如果有,則匹配失敗;如果沒有,則匹配成功。

算法舉例

下面以(({[]}) 序列爲例說明算法過程:
1、首先將這個字符串轉換成字符數組,並初始化一個空棧。

2、遍歷到第0個元素,(,爲左括號,入棧

3、後面以此類推,遍歷完第3個元素[後,棧空間應該是這樣的

4、遍歷到第4個元素]時,發現爲右括號,此時,從棧頂出棧一個左括號,即[,剛好[],匹配成一對

5、以此類推,直到第6個元素),都是匹配的

6、此時,序列已經遍歷完畢,但是棧不是空的,所以原序列匹配失敗。

代碼

棧類

這裏我使用了鏈棧,鏈表就沒有自己寫了,用了Java現成的LinkedList<T>

/**
 * 棧類,這裏使用鏈棧
 */
class MyStack{
    private int num;
    private LinkedList<Character> data;

    public MyStack(){
        this.num = 0;
        data = new LinkedList<Character>();
    }

    /**
     * 判斷棧是否爲空
     * @return
     */
    public boolean isEmpty(){
        return num == 0 ? true : false;
    }

    /**
     * 入棧
     * @param ch
     */
    public void push(Character ch){
        this.data.add(ch);
        this.num++;
    }

    /**
     * 出棧
     * @return
     */
    public Character pop(){
    	 //棧爲空時,返回' '
        if(this.isEmpty()){
            return ' ';
        }
        Character ch = this.data.remove(data.size()-1);
        this.num--;
        return ch;
    }
}

括號匹配核心算法

    /**
     * 核心方法
     * @param s
     * @return
     */
    public boolean isValid(String s) {
        char[] temp = s.toCharArray();
        MyStack stack = new MyStack();
        boolean flag = true;
        for(int i = 0 ; i < temp.length ; i++){
            //左括號,入棧
            if(temp[i] == '(' || temp[i] == '{' || temp[i] == '['){
                stack.push(temp[i]);
            }
            else{
                //右括號,出棧
                char left = stack.pop();
                //如果從棧中取出空值,說明棧已空,但還有右括號存在,肯定不匹配
                if(left == ' ') {
                    flag = false;
                }
                //如果左右括號不匹配,則失敗
                if(!check(left,temp[i])){
                    flag = false;
                }
            }
        }
        //循環完畢後,若棧不空,說明左括號個數大於右括號,不匹配
        if(flag){
            if(!stack.isEmpty()){
                flag = false;
            }
        }
        return flag;
    }
}

完整代碼

import java.util.LinkedList;

/**
 * 括號匹配問題(Blog)
 */

/**
 * 棧類,這裏使用鏈棧
 */
class MyStack{
    private int num;
    private LinkedList<Character> data;

    public MyStack(){
        this.num = 0;
        data = new LinkedList<Character>();
    }

    /**
     * 判斷棧是否爲空
     * @return
     */
    public boolean isEmpty(){
        return num == 0 ? true : false;
    }

    /**
     * 入棧
     * @param ch
     */
    public void push(Character ch){
        this.data.add(ch);
        this.num++;
    }

    /**
     * 出棧
     * @return
     */
    public Character pop(){
        //棧爲空時,返回' '
        if(this.isEmpty()){
            return ' ';
        }
        Character ch = this.data.remove(data.size()-1);
        this.num--;
        return ch;
    }
}

class Solution {

    /**
     * 判定左右括號是否匹配
     * @param left
     * @param right
     * @return
     */
    private boolean check(char left , char right){
        if(left == '('){
            return right == ')' ? true : false;
        }

        if(left == '['){
            return right == ']' ? true : false;
        }

        if(left == '{'){
            return right == '}' ? true : false;
        }
        return false;
    }

    /**
     * 核心方法
     * @param s
     * @return
     */
    public boolean isValid(String s) {
        char[] temp = s.toCharArray();
        MyStack stack = new MyStack();
        boolean flag = true;
        for(int i = 0 ; i < temp.length ; i++){
            //左括號,入棧
            if(temp[i] == '(' || temp[i] == '{' || temp[i] == '['){
                stack.push(temp[i]);
            }
            else{
                //右括號,出棧
                char left = stack.pop();
                //如果從棧中取出空值,說明棧已空,但還有右括號存在,肯定不匹配
                if(left == ' ') {
                    flag = false;
                }
                //如果左右括號不匹配,則失敗
                if(!check(left,temp[i])){
                    flag = false;
                }
            }
        }
        //循環完畢後,若棧不空,說明左括號個數大於右括號,不匹配
        if(flag){
            if(!stack.isEmpty()){
                flag = false;
            }
        }
        return flag;
    }
}

public class Main {

    public static void main(String[] args) {
	// write your code here
        Solution solution = new Solution();
        System.out.println(solution.isValid("(({[]})"));
    }
}

運行結果

(({[]})的運行結果

false
Process finished with exit code 0

與我們之前預測的一致。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章