1. 程式人生 > >NYOJ-15-括號匹配(二)

NYOJ-15-括號匹配(二)

描述
給你一個字串,裡面只包含”(“,”)”,”[“,”]”四種符號,請問你需要至少新增多少個括號才能使這些括號匹配起來。
如:
[]是匹配的
([])[]是匹配的
((]是不匹配的
([)]是不匹配的
輸入
第一行輸入一個正整數N,表示測試資料組數(N<=10)
每組測試資料都只有一行,是一個字串S,S中只包含以上所說的四種字元,S的長度不超過100
輸出
對於每組測試資料都輸出一個正整數,表示最少需要新增的括號的數量。每組測試輸出佔一行
樣例輸入
4
[]
([])[]
((]
([)]
樣例輸出
0
0
3
2

這道題原本想著用棧實現,然而嘗試了許久皆以失敗告終,然後嘗試用刪括號的辦法解決,程式碼如下(此程式碼存在bug——部分資料無法通過):

//問題程式碼
#include <stdio.h>
#include <string.h>
#define MIN(a, b) a > b ? b : a

int main(int argc, const char * argv[])
{
    int N, i, j;
    int len, tag, count, min;
    char S[101];
    scanf("%d", &N);
    while (N--)
    {
        int A[101];
        scanf("%s", S);
        len = (int
)strlen(S); tag = 1; count = 0; min = 101; //刪除匹配的括號(中間沒有其它括號) while (tag) { tag = 0; for (i = 0; i < len; i++) { if (S[i] == '(') { for (j = i + 1; j < len; ) { if
(S[j] == ')') { S[i] = ' '; S[j] = ' '; i = j; tag++; break; } else if (S[j] == ' ') { j++; } else { break; } } } else if (S[i] == '[') { for (j = i + 1; j < len; j++) { if (S[j] == ']') { S[i] = ' '; S[j] = ' '; i = j; tag++; break; } else if (S[j] == ' ') { j++; } else { break; } } } } } //將剩下括號整合到兩個陣列中 for (i = 0; i < len; i++) { if (S[i] != ' ') { A[count] = S[i]; S[count++] = S[i]; } } //再次刪除括號,刪除匹配的()(中間允許有其它括號) tag = 0; //刪除的個數 for (i = 0; i < count; i++) { if (A[i] == '(') { for (j = i + 1; j < count; j++) { if (A[j] == ')') { A[i] = ' '; A[j] = ' '; tag += 2; break; } } } } min = MIN(min, count - tag); //取最少 //再次刪除括號,刪除匹配的[](中間允許有其它括號) tag = 0; //刪除的個數 for (i = 0; i < count; i++) { if (S[i] == '[') { for (j = i + 1; j < count; j++) { if (S[j] == ']') { S[i] = ' '; S[j] = ' '; tag += 2; break; } } } } min = MIN(min, count - tag); //取最少 printf("%d\n", min); } return 0; }

為了除去這個bug我嘗試了許久,亦以失敗告終,最後只好用dp來做,當然,dp思考狀態轉移方程有些難度,但是想通了這個後,一切就迎刃而解了。

#include <stdio.h>
#include <string.h>

#define MAX_LEN 101
#define min(a,b) (a) > (b) ? (b) : (a)

int isMatch(char a, char b);

int main()
{
    int N;
    scanf("%d", &N);
    int i, j, k, tmp;
    int length = 0;
    char str[MAX_LEN];
    int data[MAX_LEN][MAX_LEN];

    while (N--)
    {
        memset(data,0,sizeof(data));

        scanf("%s",str+1);

        length = (int)strlen(str + 1);

        for (i = 1; i <= length; i++)
            data[i][i] = 1;
        //dp[i][j]從第i + 1個數到第j個數匹配str[i]的右(小或中)括號
        //結果為兩種,一種是在不同位置的匹配後結果取最小,一種是不匹配結果取最小
        for (j = 1; j <= length; j++)
        {
            for (i = j - 1; i >= 1; i--)
            {
                tmp = 0x1ffff; //給定一個最大的初始值

                for (k = i + 1; k <= j; k++)
                {
                    //i、j、k的位置關係是1 ≤ (i < k ≤) j ≤ length 
                    if (isMatch(str[i], str[k]))
                    {
                        tmp = min(tmp ,(data[i + 1][k - 1] + data[k + 1][j]));
                    }
                }

                data[i][j] = min(tmp, data[i + 1][j] + 1);
            }
        }
        //從第一個到第length個數插入括號數量最少
        printf("%d\n", data[1][length]);    
    }
    return 0;
}

//判斷是否匹配
int isMatch(char a, char b)
{
    if ((a == '(' && b == ')') || (a == '[' && b == ']'))
    {
        return 1;
    }
    return 0;
}