算法学习笔记(九)有限状态机 FSM 的应用

一个问题:Beautiful String

这是2014微软校招的编程题,题意大致如下:
如果一个字符串包括三组或者更多组的连续升序字母,每组长度相等,那么我们就称这个字符串是Beautiful String

  • 符合Beautiful String举例:abc, cde, aabbcc, aaabbbccc
  • 不符Beautiful String举例:abd,cba,aabbc,zab
    输入一个只含有小写字母的字符串,如果它含有一个Beautiful的子串,就输出YES,否则输出NO
  • 输入: 第一行是案例个数,之后的每一行是一个数字,一个字符串,数字表示字符串长度,长度小于10MB
  • 输出:YES 或 NO

有限状态机 FSM 定义

有限状态机(Finite-state machine)又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。常用与:正则表达式引擎,编译器的词法和语法分析,游戏设计,网络协议,企业应用中等方面。

有限状态机 FSM 要素

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。

“现态”和“条件”是因,“动作”和“次态”是果。
1. 现态:是指当前所处的状态。
2. 条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
3. 动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态 。
4. 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

有限状态机 FSM 实现

  • while{switch/case}(推荐可读性高) 或 if/else 实现,简单粗暴,适合简单的小型状态机;
  • 用设计模式中的 state pattern,把复杂判断的逻辑简化,利于组织代码;
  • 用状态表设计,建立状态表和动作查询表,根据状态表、事件、动作表定位相应的动作处理函数,执行完成后再进行状态的切换;

Beautiful String问题的解法

分析

这个自动机规模小,直接用if/else简单的实现即可。每个状包含4个要素:

  • 当前处理的字符 current
  • 当前处理的字符数量 num_current
  • Beautiful String中上一个字符的数量 num_prev
  • 当前元素是Beautiful String中第几个元素 pos_beauty 

代码

#include<iostream>
using namespace std;

struct states {
	char current;      //  正在处理的字符
	int num_prev;      //  beautiful string中上一个元素的数量
	int num_current;   //  正在处理的字符累计的数量
	int pos_beauty;    //  正在处理的字符是 beautiful string中的第几个元素
} s = { 0, 0, 0, 0 };

int main() {
	int ncase, n;
	char c;
	cin >> ncase;
	while (ncase--) {
		cin >> n;
		bool result = false;
		while (n--) {
			cin >> c;
			if (result) {
				continue;
			}
			if (s.current == 0) {
				s.current = c;
				s.num_current = 1;
				s.pos_beauty = 1;
				continue;
			}
			if (s.current == c) {
				s.num_current++;
				if (s.num_prev != 0 && s.num_current > s.num_prev) {
					s.num_prev = 0;
					s.pos_beauty = 1;
				}
			}
			if (s.current == c - 1) {
				if (s.num_prev == 0 || s.num_current <= s.num_prev) {
					s.pos_beauty++;
				} else {
					s.pos_beauty = 2;
				}
				s.num_prev = s.num_current;
				s.num_current = 1;
			}
			if (s.current != c && s.current != c - 1) {
				s.pos_beauty = 1;
				s.num_current = 0;
				s.num_current = 1;
			}
			if (s.pos_beauty >= 3 && s.num_current == s.num_prev) {
				result = true;
			}
			s.current = c;
		}
		if (result) {
			cout << "YES" << endl;
		} else {
			cout << "NO" << endl;
		}
	}
	return 0;
}

/**  用例:
7
3
abc
4
aaab
6
abccde
3
abb
8
aaaabbcc
11
aaaabbbccde
6
aaabbc
 */

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值