確定的有窮狀態機(DFA) -- 你來看也能懂的C++代碼示例

什麼是 確定的、有窮狀態、機

啊,看這個名字,就通俗易懂了嘛。首先它是個機,幹嘛用的機我說一下:模式串篩選用的機。

常用於從複雜的字符串中篩選有效信息,可以是敏感詞啊、詞法編輯(編譯器使用)等方面。
當然,這是常用,別人這麼用。

它這個功能特性啊,我很喜歡。確定、有窮狀態,能想到什麼?圖,流程圖!
再細想,什麼流程圖?動態流程圖,是吧,很自然吧。

普通流程圖那流程都鎖死了,按部就班就好了,但是動態流程就不一樣了,可能有的人不知道什麼叫動態流程圖,不知道正常,我剛起的名字。動態聯編知道吧,就那意思。

我覺得,DFA的機制很適合用於動態流程圖的實現,特別是複雜的,動態流程圖。當然,動態流程圖是可以暴力硬寫的,就是代碼肥了點而已。


跟我一起看個栗子

這也是我最初接觸到DFA的栗子,當時我就是暴力硬寫,當然,代碼肥的我都沒臉貼當時那篇博客裏去。




請你來實現一個 atoi 函數,使其能將字符串轉換成整數。

首先,該函數會根據需要丟棄無用的開頭空格字符,直到尋找到第一個非空格的字符爲止。接下來的轉化規則如下:

如果第一個非空字符爲正或者負號時,則將該符號與之後面儘可能多的連續數字字符組合起來,形成一個有符號整數。
假如第一個非空字符是數字,則直接將其與之後連續的數字字符組合起來,形成一個整數。
該字符串在有效的整數部分之後也可能會存在多餘的字符,那麼這些字符可以被忽略,它們對函數不應該造成影響。
注意:假如該字符串中的第一個非空格字符不是一個有效整數字符、字符串爲空或字符串僅包含空白字符時,則你的函數不需要進行轉換,即無法進行有效轉換。

在任何情況下,若函數不能進行有效的轉換時,請返回 0 。

提示:

本題中的空白字符只包括空格字符 ’ ’ 。
假設我們的環境只能存儲 32 位大小的有符號整數,那麼其數值範圍爲 [−231, 231 − 1]。如果數值超過這個範圍,請返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

示例 1:

輸入:42”
輸出: 42
示例 2:

輸入: " -42"
輸出: -42
解釋: 第一個非空白字符爲 ‘-, 它是一個負號。
我們儘可能將負號與後面所有連續出現的數字組合起來,最後得到 -42
示例 3:

輸入:4193 with words”
輸出: 4193
解釋: 轉換截止於數字 ‘3’ ,因爲它的下一個字符不爲數字。
示例 4:

輸入: “words and 987”
輸出: 0
解釋: 第一個非空字符是 ‘w’, 但它不是數字或正、負號。
因此無法執行有效的轉換。
示例 5:

輸入:-91283472332”
輸出: -2147483648
解釋: 數字 “-91283472332” 超過 32 位有符號整數範圍。
因此返回 INT_MIN (231)

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/string-to-integer-atoi
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。


DFA圖解

我們的程序在每個時刻有一個狀態 s,每次從序列中輸入一個字符 c,並根據字符 c 轉移到下一個狀態 s’。這樣,我們只需要建立一個覆蓋所有情況的從 s 與 c 映射到 s’ 的表格即可解決題目中的問題。

在這裏插入圖片描述

上面這個圖是不是看不太懂,沒關係,我也看不懂。
但是下面這個表那得看懂:

在這裏插入圖片描述
是吧,第一欄是輸入,第一列是狀態。其他部分就是特定狀態下,遇到特定輸入,會觸發什麼狀態。

這個表嘛,當狀態爲in_number的時候意味着可以計數了,爲signed的時候意味着是符號,爲end的時候就意味着該收拾收拾走了。

那,該怎麼把這個錶轉換爲代碼呢?


DFA示例實現代碼

#include<iostream>

#include<vector>

using namespace std;

int DFA(vector<char>& cvec)
{
	vector<vector<int>> vec = { {0,1,2,3},{3,3,2,3},{3,3,2,3},{3,3,3,3} };	//DFA

	int stat = 0;//實時狀態,初始化爲0

	int ret = 0;	//數據紀錄,姑且初始化爲0吧
	int flag = 1;//正負號紀錄

	for (int sz = 0; sz < cvec.size(); sz++)
	{	
		//這裏是狀態機走一圈
		if (isspace(cvec[sz]))
			stat = vec[stat][0];
		else if (cvec[sz] == '+' || cvec[sz] == '-')
			stat = vec[stat][1];
		else if (isdigit(cvec[sz]))
			stat = vec[stat][2];
		else
			stat = 3;
		
		//狀態機走完該判斷狀態了
		if (stat == 3)
			return ret * flag;
		else if (stat == 1)	//這個最多也就一次機會進了
		{
			if (cvec[sz] == '-')
				flag = -1;
		}
		else if (stat == 2) {}
			//對數據進行疊加處理,這邊建議先放到數組裏,等返回的時候(stat == 3)一次性處理
	}
}

博客推薦

這篇是來還願的,因爲我在另一篇博客中說要把DFA搞明白。

這裏推薦那篇博客,講了(KMP算法、遞歸、DFA的python版)的實現。

->力扣刷題筆記(6)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章