扩号匹配问题——递归

括号匹配问题我感觉十分有趣,它本身的难度并不是太大,但它考察的点包括了递归传递以及回溯的理解程度,将它一步步完善从开始到完成的过程,相信会对递归有一个更深的了解。

括号匹配问题

解题思路

将它简化,从最简单的问题开始,逐步的完善它。

  1. 假设问题仅仅只是一个左括号匹配一个右括号,与顺序无关。那问题就相对的比较简单了,思路就是统计左括号的个数,然后碰到右括号在抵消一个左括号。(也就是定义俩个关键值为0,一个为left,表示左括号的个数,一个为right,表示右括号的个数。从左到右遍历字符串,碰到一个左括号就left加一,碰到一个右括号就right减一(加也可以)。用递归遍历到最后一个字符的时候返回,返回的同时判断关键值的大小来决定是否能够匹配。)
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int l = 0, r = 0;    //l 表示左括号   r 表示右括号
char a[101];     //存放字符串中括号匹配的状态
void mate(char str[], int front, int rear)   
//front 表示字符串遍历开始下标,rear 表示字符串遍历结束下标
{
	if (front == rear)    //相等时遍历结束
		return;
	else {
		switch (str[front])
		{
		case '(':    //左括号
			l++; 
			mate(str, front + 1, rear);
			if (r < 0)     //是否有未匹配完的右括号
			{
				a[front] = ' ';  r++;
			}
			else   a[front] = '$';
			break;
		case ')':   //右括号
			r--;
			mate(str, front + 1, rear);
			if (l > 0)    //是否有未匹配完的左括号
			{
				a[front] = ' ';
				l--;
			}
			else   a[front] = '?';
			break;
		default :   //非括号
			mate(str, front + 1, rear);
			a[front] = ' ';
		}
	}
}
int main()
{
	char str[101];
	while (scanf("%s", str) != EOF)
	{
		cout << str << endl;
		mate(str, 0, strlen(str));
		cout << a << endl;
		l = 0; r = 0;
	}
	return 0;
}

运行结果
运行结果

左括号有 3 个,右括号有 4 个,所以左括号全部匹配,右括号 1 个未匹配,因为回溯的时候才处理,所以靠前的 1 个未匹配。很显然,问题没有解决,但我们解决了上面的第一个小问题。

  1. 找出上面代码出错的地方。按题目的意思,未匹配的右括号应该是第一个和倒数第一个右括号,但是倒数第一个没有标记出来,按题,倒数第一个左括号也未匹配,但它也没被标记。这就是出现的问题。
  2. 分析问题出现的原因。首先,俩个匹配的括号出现的顺序应该是左括号在左边,右括号在右边,那么,一个左括号要匹配的前提是左括号的右边有一个未匹配的右括号,一个右括号要匹配的前提是左括号的左边有一个未匹配的右括号,同时还有相近的相匹配的问题但是上面的代码并没有考虑到这个问题。
  3. 问题找到,接下来我们需要解决这个问题。上面说过,递归有传递和回溯的过程,上面传递的过程是从左到右,那如果左边先有了一个左括号,那么向右碰到的第一个右括号就是与这个左括号相匹配的右括号,右括号的状态是可以直接确定的,反之,回溯的过程中来处理左括号。
    总结
    在传递的过程中处理右括号 “)”,在回溯的过程中处理左括号 “(”。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int l = 0, r = 0;
char a[101];
void mate(char str[], int front, int rear)
{
	if (front == rear)
		return;
	else {
		switch (str[front])
		{
		case '(':
			l++;     //传递时统计,为右括号")"处理做准备
			mate(str, front + 1, rear);
			if (r < 0)
			 //在回溯时判断右括号")"的数量,也就是判断该左括号前面有无右括号匹配
			{
				a[front] = ' ';  r++;
			}
			else   a[front] = '$';
			break;
		case ')':
			if (l > 0)   
			 //在传递中判断左括号"("的数量,也就是判断该右括号前面有无左括号匹配
			{
				a[front] = ' ';
				l--;
			}
			else   a[front] = '?';
			mate(str, front + 1, rear);
			r--;        //回溯时统计,为左括号"("处理做准备。
			break;
		default :
			mate(str, front + 1, rear);
			a[front] = ' ';
		}
	}
}
int main()
{
	char str[101];
	while (scanf("%s", str) != EOF)
	{
		cout << str << endl;
		mate(str, 0, strlen(str));
		cout << a << endl;
		l = 0; r = 0;
	}
	return 0;
}

运行结果
运行结果
这样括号匹配问题就解决了,希望对你有帮助。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值