想象一下,你正在為你的大學課設編寫乙個小型編譯器,編譯器的任務之一(或稱子任務)將檢測括號是否匹配。
我們本文中看到的演算法可用於處理編譯器正在編譯的程式中的所有括號,並檢查是否所有括號都已配對。這將檢查給定的括號字串是否有效,是乙個重要的程式設計問題。
我們這個問題中將要處理的表示式可以包含以下三種不同型別的括號:
(),{} 以及
**在檢視如何檢查由這些括號組成的給定表示式是否有效之前,讓我們看一下該問題的簡化版本,**在簡化後的問題中,只含一種型別的括號。這麼一來,我們將會遇到的表示式是
(((((()))))) – valid
()()()() – valid
(((((((() – invalid
((()(()))) – valid
我們試著用乙個簡單的演算法來解決這一問題。
我們從表示式的左側開始,每次只處理乙個括號。
假設我們遇到乙個開括號(即 (),表示式是否無效取決於在該表示式的其餘部分的某處是否有相匹配的閉括號(即 ))。此時,我們只是增加計數器的值保持跟蹤現在為止開括號的數目。left += 1
如果我們遇到乙個閉括號,這可能意味著這樣兩種情況:
此閉括號沒有與與之對應的開括號,在這種情況下,我們的表示式無效。當 left == 0,也就是沒有未配對的左括號可用時就是這種情況。
我們有一些未配對的開括號可以與該閉括號配對。當 left > 0,也就是有未配對的左括號可用時就是這種情況。
如果我們在 left == 0 時遇到乙個閉括號(例如 )),那麼當前的表示式無效。否則,我們會減少 left 的值,也就是減少了可用的未配對的左括號的數量。
繼續處理字串,直到處理完所有括號。
如果最後我們仍然有未配對的左括號,這意味著表示式無效。
在這裡討論這個特定演算法是因為我們從該解決方案中獲得靈感以解決原始問題。
如果我們只是嘗試對原始問題採用相同的辦法,這是根本就行不通的。基於簡單計數器的方法能夠在上面完美執行是因為所有括號都具有相同的型別。因此,當我們遇到乙個閉括號時,我們只需要假設有乙個對應匹配的開括號是可用的,即假設 left > 0。
但是,在我們的問題中,如果我們遇到 ],我們真的不知道是否有相應的 [ 可用。你可能會問:
為什麼不為不同型別的括號分別維護乙個單獨的計數器?
這可能不起作用,因為括號的相對位置在這裡也很重要。例如:[{]
如果我們只是在這裡維持計數器,那麼只要我們遇到閉合方括號,我們就會知道此處有乙個可用的未配對的開口方括號。但是,最近的未配對的開括號是乙個花括號,而不是乙個方括號,因此計數方法在這裡被打破了。
方法:棧
讓我們看看下面的這個想法,從整體表示式中一次刪除乙個較小的表示式,因為這是乙個有效的表示式,我們最後剩留下乙個空字串。
在表示問題的遞迴結構時,棧資料結構可以派上用場。我們無法真正地從內到外處理這個問題,因為我們對整體結構一無所知。但是,棧可以幫助我們遞迴地處理這種情況,即從外部到內部。
讓我們看看使用棧作為該問題的中間資料結構的演算法。
演算法
初始化棧 s。
一次處理表示式的每個括號。
如果遇到開括號,我們只需將其推到棧上即可。這意味著我們將稍後處理它,讓我們簡單地轉到前面的 子表示式。
如果我們遇到乙個閉括號,那麼我們檢查棧頂的元素。如果棧頂的元素是乙個 相同型別的 左括號,那麼我們將它從棧中彈出並繼續處理。否則,這意味著表示式無效。
如果到最後我們剩下的棧中仍然有元素,那麼這意味著表示式無效
括號匹配問題
時間限制 3000 ms 記憶體限制 65535 kb 難度 3 描述 現在,有一行括號序列,請你檢查這行括號是否配對。輸入第一行輸入乙個數n 0輸出 每組輸入資料的輸出佔一行,如果該字串中所含的括號是配對的,則輸出yes,如果不配對則輸出no 樣例輸入 3 樣例輸出 no noyes 基本演算法思...
括號匹配問題
假設表示式中包含三種括號 圓括號 方括號和花括號,它們可以相互巢狀,如 等均為正確的格式,而等為不正確的格式。以下為演算法程式 括號匹配問題 include include int main char ch while ch getchar eof count 0 break case if cou...
括號匹配問題
問題描述 假設表示式中允許包含兩種括號 圓括號與方括號,其巢狀的順序隨意。如 或 等為正確的匹配 而 或者 或者 均為錯誤的匹配。現要求編寫程式,判斷輸入的一行括號是否是匹配的,如果是匹配的,輸出yes,否則輸出no。解題思路 檢驗括號是否是匹配的方法可以用 期待的急迫程度 這個概念來描述。例如考慮...