Bracket Matching | String Processing

10. Bracket Matching

Grades 10 opening time Thursday, September 10, 2020 12:00
discount 0.8 Discount time Thursday, September 17, 2020 09:00
Late submission allowed no Closing time Saturday, October 10, 2020 23:00

Description

The bracket sequence is a non-empty sequence composed of the left bracket "(" and the right bracket ")". It is easy to determine the validity of a bracket sequence. For example, "()", "(())()", "(()())", "(()(()))", "()()()" are all legal, while " )", "(", "(()", "(()))(" are all illegal.

Given n bracket sequences, pair them in pairs, and ask how many pairs of legal bracket sequences can be formed. (Each bracket sequence can only appear in a pair)

Input

Enter the integer n in the first line to indicate that there are n bracket sequences, and in the next n lines, enter n bracket sequences.

Output

Output an integer that represents the largest number of pairs of legal bracket sequences.

Hint

The first set of use cases can form two pairs of legal bracket sequences, namely "(( )())" and "( )".


1. Simplified operation of bracket sequence

       This question is a classic bracket matching problem. Let's first look at a single bracket string. How do we judge that it matches? Take the bracket string ((()())) as an example, it looks like it matches at a glance! Then how do we think about him in a procedural way?
       It's not as good as this: we prepare a container stack with only one end open , and it is stipulated that we can only put the top of this container in order, or take out the top . As you will learn later, this kind of container is called a stack, which is a very common data structure. The following is a schematic diagram of the basic operation of the stack, just understand this model.

Java Edition-Data Structure-Stack | The Road of Xiaobai Program

 

       Next, we need to simplify the bracket string through the above container, so that the string we get after simplifying, the conclusion of whether it matches is the same as the original string. Traverse each element t in the bracket string in turn, and the specific operations for each element are as follows (if you don't understand this process, try it yourself manually):

  • If the top element of the container stack (stack is not empty) matches t: remove the top element of the stack;
  • If the container stack is empty or the top element of the container stack does not match t: put the element t on the top of the stack

       After the traversal is complete, our simplified bracket string is in the container . If the container stack is empty, the bracket string itself is matched, otherwise it must not match .


 2. Ideas for this question       

    Let's take a look at the requirements of this question again. We have to judge whether the two bracket strings s1 and s2 can form a matching bracket string. Then there should be two situations:

  • s1 and s2 are all matched parentheses, and they must still match.
  • Both s1 and s2 are not matchable strings, but their simplified strings can match each other.

       Here we focus on the second case, after the match if simplified, then two strings must be simplified uniform (only left parenthesis / right parenthesis one), and simplify two strings the same number of elements contrary species .

For example, s1: )(())) can be simplified to ))
For example, s2: (()( can be simplified to ((The
simplified two strings can be matched, so the original string can also be matched.


        So based on the above summary, we sorted out the algorithm of this problem:
        for the input n strings s, we simplified them one by one, and recorded the simplified results. If it is empty, record the number of matching strings; otherwise, record them as several left parentheses/ several right parentheses, and record the numbers in the arrays left and right. (If there is a left parenthesis and a right parenthesis after simplification, it must not match any string, just ignore it) The

        question requires that each string can only be matched once, and left[i] records the length of the simplified i The number of strings in a left parenthesis is the same for the right array. Then our final total number of matches should be calculated as follows: the calc strings that are matched by themselves can be matched into the calc/2 group at most; traverse the left array and take min (left[i], right[i]).


3. Code implementation

       After understanding the above ideas, writing code is easier. It may be the first time to contact the stack, and I don't know how to implement this model by programming. The following code is implemented through a one-dimensional array and moving subscripts . This is a way of c code to implement the stack. In fact, it is even easier if it is C++. There is a packaged stack in the C++ stack library. We can directly define it like basic data types (such as int), and then use it directly. However, in this subject music, only the c code is allowed to be handed in. I will change it to c and paste it here for emmmm... The complete code is as follows:

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

#define MAX_LEN 100050


/* 分别记录化简之后,全为左括号/右括号的串的个数,下标代表括号个数
 * 如:left[3]代表"((("有多少个,right[2]代表"))"有多少个 */
long long left[MAX_LEN] = {0}, right[MAX_LEN] = {0};
long long calc = 0;  //记录化简之和位空串的个数(该串化简前本身就是合法的)

int match(char c1, char c2) {
    if(c1 == '(' && c2 == ')')
        return 1;
    else
        return 0;
}

/* 处理字符串s,将其化为最简形式
 * 并将最简形式记录在left/right数组中 */
void dealStr(char s[]) {
    /* 利用栈依次考虑每一个字符
     * 最终将其最简形式留在栈内 */
    char stack[MAX_LEN];
    int top_index = -1;  //指向栈顶元素下标
    for (int i = 0; i < strlen(s); i++) {
        //当栈非空 且 栈顶与待加入元素相匹配时
        if (top_index != -1 && match(stack[top_index], s[i]))
            top_index--;  //出栈
        else
            stack[++top_index] = s[i];  //入栈
    }
    /* 处理其最简形式,进行记录 */
    //最简形式为空,本身就是匹配的
    if (top_index == -1) {
        calc++;
        return;
    }

    char c = stack[top_index];
    int count = top_index + 1; //记录下化简完后的栈内剩余元素

    while (top_index >= 0) {
        if (stack[top_index] != c)  //栈内剩余字符串不是同号的
            return;
        top_index--;
    }

    if (c == '(')
        left[count]++;
    else
        right[count]++;
}


int main() {
    int n;
    char str[MAX_LEN];
    scanf("%d\n", &n);  //一定记得吸去换行符

    /* 依次读入初始字符串并进行处理 */
    for (int i = 0; i < n; i++) {
        scanf("%s", str);
        dealStr(str);
    }

    //本身就是匹配的字符串,两两匹配
    long long ans = calc / 2;
    for (int i = 0; i < MAX_LEN; i++) {
        ans += left[i] < right[i] ? left[i] : right[i];
    }

    printf("%lld\n", ans);
}


Welcome to pay attention to the personal public account "  Chicken Wing Programming" , here is a serious and well-behaved code farmer.

---- Be the most well-behaved blogger and the most solid programmer ----

Aim to write each article carefully, and usually summarize the notes into push updates~

Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_43787043/article/details/108518190