原文鏈接:
http://blog.csdn.net/beiyeqingteng/article/details/7695274
問題:
給你一個字符串,裏面只包含"(",")","[","]"四種符號,請問你需要至少添加多少個括號才能使這些括號匹配起來。
如:
[]是匹配的,所需括號個數爲 0.
([])[]是匹配的, 所需括號個數爲 0.
((]是不匹配的, 所需最少括號個數爲 3.
([)]是不匹配的,所需最少括號個數爲 2.
分析:
此題來自:http://blog.csdn.net/coolanfei/article/details/7475542, 作者同時給出了正確答案。但是,感覺答案還不是特別的詳細,也不是特別容易懂。所以,在此寫下自己的分析思路。
1. 我們用 mb[i][j] 表示從位置 i 到字符位置 j 所需的最少括號數。假定字符串是 “[ ( )”, 那麼 mb[0][0] = mb[1][1] = mb[2][2] = 1。
2. 如果我們要算mb[i][j+1], 那麼,最壞的情況是使得沒有被匹配的括號數增加了,即 mb[i][j+1] 最多爲 min( mb[i][j] + 1, mb[i+1][j+1] + 1). 但是,這可能不是我們想要的答案,因爲在剛纔的例子裏,即:假定字符串是 “[ ( )”, 那麼 mb[0][1] = mb[0][0] + 1= 2, 但是 mb[1][2] 卻不等於 mb[1][1] + 1.
3. 那麼,什麼情況下mb[i][j+1] = mb[i][j] + 1?只有當 字符串裏從i 到 j 沒有任何字符與第 j + 1 個字符匹配的時候。但是,如果存在和第 j + 1 個字符匹配的情況,問題就不一樣了。
4. 假設在i 到 j 之間存在一個字符(比如在位置 k)與第 j + 1 個字符匹配,那麼我們相當於把原來的字符串分成了兩個部分mb[i][k-1] 和 mb[k+1][j], 因爲第k 個 和 j + 1 個字符已經匹配掉了。而且,我們不會再考慮 i 到 k - 1 的字符會和 k + 1 到 j 之間的字符匹配的情況,因爲我們已經把這兩個部分完全分開了(很重要的一點,這也是我當時思考很久的地方)。話句話說 mb[i][j+1] = min(min( mb[i][j] + 1, mb[i+1][j+1] + 1), mb[i][k-1] + mb[k+1][j]).
有了這樣的分析,我們可以利用動態規劃的思路來解決這樣的問題。代碼如下:
- static boolean match(char a, char b){
- if(a == '(' && b == ')')
- return true;
- if(a == '[' && b == ']')
- return true;
- return false;
- }
- public static void minBrace(String s) {
- int size = s.length();
- // we begin with mb[1][1]
- int[][] mb = new int[size + 1][size + 1];
- for(int i = 1; i <= size; ++i){
- mb[i][i] = 1;
- }
- // d refers to the distance between i and j, that is d = j - i
- for(int d = 1; d < size; d++){
- for (int i = 1; i + d <= size; i++) {
- int j = i + d;
- // the worst case
- mb[i][j] = Math.min(mb[i][j - 1], mb[i + 1][j]) + 1;
- // the case in which a char between i and j (= i + d) matches
- // the character at position j + 1
- for (int k = i ; k <= j - 1; k++ ) {
- if (match(s.charAt(k - 1), s.charAt(j - 1)) == true) {
- mb[i][j] = Math.min(mb[i][j], mb[i][k - 1] + mb[k + 1] [j - 1]);
- }
- }
- }
- }
- System.out.println(mb[1][size]);
- }