有效的括號

給定一個只包括 '('煌寇,')','{'逾雄,'}'阀溶,'[',']' 的字符串鸦泳,判斷字符串是否有效银锻。

有效字符串需滿足:

左括號必須用相同類型的右括號閉合。
左括號必須以正確的順序閉合做鹰。
注意空字符串可被認(rèn)為是有效字符串击纬。

示例 1:

輸入: "()"
輸出: true
示例 2:

輸入: "()[]{}"
輸出: true
示例 3:

輸入: "(]"
輸出: false
示例 4:

輸入: "([)]"
輸出: false
示例 5:

輸入: "{[]}"
輸出: true

思路

想象一下,你正在為你的大學(xué)課設(shè)編寫一個小型編譯器钾麸,編譯器的任務(wù)之一(或稱子任務(wù))將檢測括號是否匹配更振。

我們本文中看到的算法可用于處理編譯器正在編譯的程序中的所有括號,并檢查是否所有括號都已配對饭尝。這將檢查給定的括號字符串是否有效肯腕,是一個重要的編程問題。

我們這個問題中將要處理的表達(dá)式可以包含以下三種不同類型的括號:

  • ()钥平,
  • {} 以及
  • []

在查看如何檢查由這些括號組成的給定表達(dá)式是否有效之前实撒,讓我們看一下該問題的簡化版本,在簡化后的問題中涉瘾,只含一種類型的括號奈惑。這么一來,我們將會遇到的表達(dá)式是

(((((()))))) -- VALID

()()()() -- VALID

(((((((() -- INVALID

((()(()))) -- VALID

上我們試著用一個簡單的算法來解決這一問題睡汹。

  1. 我們從表達(dá)式的左側(cè)開始肴甸,每次只處理一個括號。
  2. 假設(shè)我們遇到一個開括號(即 ()囚巴,表達(dá)式是否無效取決于在該表達(dá)式的其余部分的某處是否有相匹配的閉括號(即 ))原在。此時,我們只是增加計數(shù)器的值保持跟蹤現(xiàn)在為止開括號的數(shù)目彤叉。left += 1
  3. 如果我們遇到一個閉括號庶柿,這可能意味著這樣兩種情況:
    1. 此閉括號沒有與與之對應(yīng)的開括號,在這種情況下秽浇,我們的表達(dá)式無效浮庐。當(dāng) left == 0,也就是沒有未配對的左括號可用時就是這種情況。
    2. 我們有一些未配對的開括號可以與該閉括號配對审残。當(dāng) left > 0梭域,也就是有未配對的左括號可用時就是這種情況。
  4. 如果我們在 left == 0 時遇到一個閉括號(例如 ))搅轿,那么當(dāng)前的表達(dá)式無效病涨。否則,我們會減少 left 的值璧坟,也就是減少了可用的未配對的左括號的數(shù)量既穆。
  5. 繼續(xù)處理字符串,直到處理完所有括號雀鹃。
  6. 如果最后我們?nèi)匀挥形磁鋵Φ淖罄ㄌ柣霉ぃ@意味著表達(dá)式無效。

在這里討論這個特定算法是因為我們從該解決方案中獲得靈感以解決原始問題黎茎。為了更好地理解我們討論的算法会钝,請觀看下面的動畫演示。

image.png

1 / 12

如果我們只是嘗試對原始問題采用相同的辦法工三,這是根本就行不通的迁酸。基于簡單計數(shù)器的方法能夠在上面完美運行是因為所有括號都具有相同的類型俭正。因此奸鬓,當(dāng)我們遇到一個閉括號時,我們只需要假設(shè)有一個對應(yīng)匹配的開括號是可用的掸读,即假設(shè) left > 0串远。

但是,在我們的問題中儿惫,如果我們遇到 ]澡罚,我們真的不知道是否有相應(yīng)的 [ 可用。你可能會問:

為什么不為不同類型的括號分別維護(hù)一個單獨的計數(shù)器肾请?

這可能不起作用留搔,因為括號的相對位置在這里也很重要。例如:

如果我們只是在這里維持計數(shù)器铛铁,那么只要我們遇到閉合方括號隔显,我們就會知道此處有一個可用的未配對的開口方括號。但是饵逐,最近的未配對的開括號是一個花括號括眠,而不是一個方括號,因此計數(shù)方法在這里被打破了倍权。


方法:棧

關(guān)于有效括號表達(dá)式的一個有趣屬性是有效表達(dá)式的子表達(dá)式也應(yīng)該是有效表達(dá)式掷豺。(不是每個子表達(dá)式)

此外,如果仔細(xì)查看上述結(jié)構(gòu),顏色標(biāo)識的單元格將標(biāo)記開閉的括號對当船。整個表達(dá)式是有效的题画,而它的子表達(dá)式本身也是有效的。這為問題提供了一種遞歸結(jié)構(gòu)生年。例如婴程,考慮上圖中兩個綠色括號內(nèi)的表達(dá)式廓奕。開括號位于索引 1抱婉,相應(yīng)閉括號位于索引 6

如果每當(dāng)我們在表達(dá)式中遇到一對匹配的括號時桌粉,我們只是從表達(dá)式中刪除它蒸绩,會發(fā)生什么?

讓我們看看下面的這個想法铃肯,從整體表達(dá)式中一次刪除一個較小的表達(dá)式患亿,因為這是一個有效的表達(dá)式,我們最后剩留下一個空字符串。

image.png

1 / 5

在表示問題的遞歸結(jié)構(gòu)時,棧數(shù)據(jù)結(jié)構(gòu)可以派上用場谱轨。我們無法真正地從內(nèi)到外處理這個問題衷畦,因為我們對整體結(jié)構(gòu)一無所知。但是植酥,棧可以幫助我們遞歸地處理這種情況,即從外部到內(nèi)部雾消。

讓我們看看使用棧作為該問題的中間數(shù)據(jù)結(jié)構(gòu)的算法。

算法

  1. 初始化棧 S挫望。
  2. 一次處理表達(dá)式的每個括號立润。
  3. 如果遇到開括號,我們只需將其推到棧上即可媳板。這意味著我們將稍后處理它桑腮,讓我們簡單地轉(zhuǎn)到前面的 子表達(dá)式
  4. 如果我們遇到一個閉括號蛉幸,那么我們檢查棧頂?shù)脑氐降H绻麠m數(shù)脑厥且粋€ 相同類型的 左括號,那么我們將它從棧中彈出并繼續(xù)處理巨缘。否則添忘,這意味著表達(dá)式無效。
  5. 如果到最后我們剩下的棧中仍然有元素若锁,那么這意味著表達(dá)式無效搁骑。

我們來看一下該算法的動畫演示,然后轉(zhuǎn)到實現(xiàn)部分。

現(xiàn)在讓我們看看該算法是如何實現(xiàn)的仲器。

Java版本

class Solution {

  // Hash table that takes care of the mappings.
  private HashMap<Character, Character> mappings;

  // Initialize hash map with mappings. This simply makes the code easier to read.
  public Solution() {
    this.mappings = new HashMap<Character, Character>();
    this.mappings.put(')', '(');
    this.mappings.put('}', '{');
    this.mappings.put(']', '[');
  }

  public boolean isValid(String s) {

    // Initialize a stack to be used in the algorithm.
    Stack<Character> stack = new Stack<Character>();

    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);

      // If the current character is a closing bracket.
      if (this.mappings.containsKey(c)) {

        // Get the top element of the stack. If the stack is empty, set a dummy value of '#'
        char topElement = stack.empty() ? '#' : stack.pop();

        // If the mapping for this bracket doesn't match the stack's top element, return false.
        if (topElement != this.mappings.get(c)) {
          return false;
        }
      } else {
        // If it was an opening bracket, push to the stack.
        stack.push(c);
      }
    }

    // If the stack still contains elements, then it is an invalid expression.
    return stack.isEmpty();
  }
}

GO 語言版本如下:

package valid_parentheses

func isValid(str string) bool {
    s := new(stack)

    for _, b := range str {
        switch b {
        case '(', '[', '{':
            s.push(b)
        case ')', ']', '}':
            if r, ok := s.pop(); !ok || r != matching[b] {
                return false
            }
        }
    }

    if len(*s) > 0 {
        return false
    }

    return true
}

var matching = map[rune]rune{
    ')': '(',
    ']': '[',
    '}': '{',
}

type stack []rune

func (s *stack) push(b rune) {
    *s = append(*s, b)
}

func (s *stack) pop() (rune, bool) {
    if len(*s) > 0 {
        res := (*s)[len(*s)-1]
        *s = (*s)[:len(*s)-1]
        return res, true
    }

    return 0, false
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煤率,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子乏冀,更是在濱河造成了極大的恐慌蝶糯,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辆沦,死亡現(xiàn)場離奇詭異昼捍,居然都是意外死亡,警方通過查閱死者的電腦和手機肢扯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門妒茬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蔚晨,你說我怎么就攤上這事乍钻。” “怎么了铭腕?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵银择,是天一觀的道長。 經(jīng)常有香客問我累舷,道長浩考,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任笋粟,我火速辦了婚禮怀挠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘害捕。我一直安慰自己绿淋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布尝盼。 她就那樣靜靜地躺著吞滞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盾沫。 梳的紋絲不亂的頭發(fā)上裁赠,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音赴精,去河邊找鬼佩捞。 笑死,一個胖子當(dāng)著我的面吹牛蕾哟,可吹牛的內(nèi)容都是我干的一忱。 我是一名探鬼主播莲蜘,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼帘营!你這毒婦竟也來了票渠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芬迄,失蹤者是張志新(化名)和其女友劉穎问顷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禀梳,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡杜窄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了出皇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羞芍。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡哗戈,死狀恐怖郊艘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唯咬,我是刑警寧澤纱注,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站胆胰,受9級特大地震影響狞贱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜀涨,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一瞎嬉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧厚柳,春花似錦氧枣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碳想,卻和暖如春烧董,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背胧奔。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工逊移, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人龙填。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓胳泉,卻偏偏與公主長得像啡浊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子胶背,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)巷嚣,也就是一...
    悟名先生閱讀 4,149評論 0 13
  • 題目: 有效的括號 給定一個只包括 '(',')'钳吟,'{'廷粒,'}','['红且,']' 的字符串坝茎,判斷字符串是否有效...
    韋弦Zhy閱讀 1,335評論 0 1
  • Unicode?標(biāo)準(zhǔn)附錄#9 UNICODE雙向算法#### 摘要#### 本附件是一份關(guān)于字符定位的規(guī)范,主要描...
    Eriice閱讀 4,759評論 0 6
  • 20. 有效的括號 描述 給定一個只包括 '('暇番,')'嗤放,'{','}'壁酬,'['次酌,']' 的字符串,判斷字符串是否...
    GoMomi閱讀 123評論 0 0
  • 之前寫了兩篇 感覺太簡單的沒什么意思 就一直擱下懶得寫了 今天做題的時候碰到了個有意思的 就記錄一下吧 有效的括號...
    Garvey叫獸閱讀 540評論 0 0