ZOJ1016-Parencodings(水题)

题意

令 S = s1 s2 … s2n 为格式正确的括号。 S可以两种不同的方式编码:
(1) 通过整数序列 P = p1 p2 … pn,其中pi是S中的第 i 个右括号之前的左括号的个数(记为P序列)。
(2) 通过整数序列 W = w1 w2 … wn,其中wi是字符串S中第 i 个右括号往左数遇到和它相匹配的左括号时经过的左括号个数。(记为W序列)。

以下是上述编码的示例:

S (((()()())))
P 4 5 6 6 6 6
W 1 1 1 4 5 6

编写一个程序,将格式正确的字符串的P序列转换为同一字符串的W序列。

输入

输入的第一行包含一个整数t(1 <= t <= 10),测试用例的数量,后跟每个测试用例的输入数据。每个测试用例的第一行是整数n(1 <= n <= 20),第二行是格式正确的字符串的P序列。它包含n个正整数,用空格分隔,代表P序列。

输出

输出由恰好对应于测试用例的t行组成。对于每个测试用例,输出行应包含n个整数,这些整数描述对应于给定P序列的字符串的W序列。

样例

Sample Input
2
6
4 5 6 6 6 6
9
4 6 6 6 6 8 9 9 9

Sample Output
1 1 1 4 5 6
1 1 2 4 5 1 1 3 9

解题思路

水题,可以一眼看出来暴力可以搞定,但思考了有一会能否在O(N)时间内算出,但没有太有效的想法。
首先通过P序列的第一个数字就可以确定的是第一个右括号前面的左括号数量,将这些左括号存入数组中,再存入一个右括号,而后每一个P序列数字,都计算与上一个数字之间的差值获得两个右括号之间包含的左括号数量,如此便可以将S字符串完整列出。
由于本题n的大小为20,数据范围极小,可以直接遍历每一个右括号向左数会经过几个左括号才能到达与自己匹配的左括号。

AC代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int main() {
	char P[25];
	int W[25];
	int t,c;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		int j = 0,k = 0;//j记录右括号数量,k记录左括号数量
		for (int i = 0; i < n; i++) {
			cin >> c;
			for (; k < c; k++) { //将两个右括号之间的左括号补齐
				P[j++] = '(';
			}
			P[j++] = ')';//将右括号放入数组
		}
		
		int dex = 0;
		for (int i = 0; i < j; i++) {
			if (P[i] == ')') {
				int sum = 0;
				for (int k = i; k >= 0; k--) {
					if (P[k] == '(') {
					// 若一个左括号被匹配了,则将这个左括号换成‘-’号,以便于后面右括号寻找匹配的左括号
						P[k] = '-';
						break;
					}
					if (P[k] == '-') //遇到‘-’号说明此处有一个被匹配的左括号,sum++;
						sum++;
				}
				W[dex++] = sum + 1; //匹配的左括号本身也要计算在其中。
			}
		}

		for (int i = 0; i < n; i++) {
			cout << W[i];
			if (i < n - 1)
				cout << " ";
		}
		cout << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值