表示数值的字符串(有限状态自动机与搜索)
文章目錄
- 題目
- 思路一
- 代碼一
- 思路二
- 代碼二
題目
思路一
考察有限狀態(tài)自動(dòng)機(jī)(參考jyd):
字符類型:
空格 「 」、數(shù)字「 0—9 」 、正負(fù)號(hào) 「 ± 」 、小數(shù)點(diǎn) 「 . 」 、冪符號(hào) 「 eE 」 。
狀態(tài)定義:
按照字符串從左到右的順序,定義以下 9 種狀態(tài):
結(jié)束狀態(tài):
合法的結(jié)束狀態(tài)有 2, 3, 7, 8 。
算法流程:
初始化:
狀態(tài)轉(zhuǎn)移循環(huán): 遍歷字符串 s 的每個(gè)字符 c 。
記錄字符類型 t : 分為四種情況。
- 當(dāng) c 為正負(fù)號(hào)時(shí),執(zhí)行 t = 's' ;
- 當(dāng) c 為數(shù)字時(shí),執(zhí)行 t = 'd' ;
- 當(dāng) c 為 e , E 時(shí),執(zhí)行 t = 'e' ;
- 當(dāng) c 為 . , 空格 時(shí),執(zhí)行 t = c (即用字符本身表示字符類型);
- 否則,執(zhí)行 t = ‘?’ ,代表為不屬于判斷范圍的非法字符,后續(xù)直接返回 false。
終止條件: 若字符類型 t 不在哈希表 maps[p] 中,說明無法轉(zhuǎn)移至下一狀態(tài),因此直接返回 False 。
狀態(tài)轉(zhuǎn)移: 狀態(tài) p 轉(zhuǎn)移至 maps[p][t] 。
返回值: 跳出循環(huán)后,若狀態(tài) p∈2,3,7,8 ,說明結(jié)尾合法,返回 True ,否則返回 False 。
再詳細(xì)說一下狀態(tài)轉(zhuǎn)移表的作用(下面代碼部分的注釋中有結(jié)合實(shí)例進(jìn)行詳解):
- 處于第 i 行表明此時(shí)遍歷到的字符是第 i+1 種狀態(tài)(可以對(duì)照上文的狀態(tài)定義)
- 那么我下一個(gè)字符可以是第 i 行中的各個(gè) key 對(duì)應(yīng)的字符。
- 如果某字符沒有寫進(jìn)第 i 行,表示 i+1 狀態(tài)的下一個(gè)字符不應(yīng)是某字符
復(fù)雜度分析:
代碼一
class Solution { public:bool isNumber(string s) {vector<map<char,int>> maps = { // 狀態(tài)轉(zhuǎn)移表 // 以第一行為例,狀態(tài)轉(zhuǎn)移表的含義為: // 開始的空格其下一個(gè)字符可以繼續(xù)是空格,也可以是符號(hào)、數(shù)字、小數(shù)點(diǎn), // 但不可是第0行不存在的e。 // 也就是為了保證字符串是數(shù)值,空格后面不能直接跟一個(gè)冪符號(hào)。{{' ', 0}, {'s', 1}, {'d', 2}, {'.', 4}}, // 開始的空格{{'d', 2}, {'.', 4}}, // 冪符號(hào)前的正負(fù)號(hào){{'d', 2}, {'.', 3}, {'e', 5}, {' ', 8}}, // 小數(shù)點(diǎn)前的數(shù)字{{'d', 3}, {'e', 5}, {' ', 8}}, // 小數(shù)點(diǎn)、小數(shù)點(diǎn)后的數(shù)字{{'d', 3}}, // 當(dāng)小數(shù)點(diǎn)前為空格時(shí),小數(shù)點(diǎn)、小數(shù)點(diǎn)后的數(shù)字{{'s', 6}, {'d', 7}}, // 冪符號(hào){{'d', 7}}, // 冪符號(hào)后的正負(fù)號(hào){{'d', 7}, {' ', 8}}, // 冪符號(hào)后的數(shù)字{{' ', 8}} // 結(jié)尾的空格};int p = 0; //起始狀態(tài)char t;for(char c : s) {if(c >= '0' && c <= '9') t = 'd';else if(c == '+' || c == '-') t = 's';else if(c == 'e' || c == 'E') t = 'e';else if(c == '.' || c == ' ') t = c;else t = '?';if(maps[p].find(t) == maps[p].end()) return false;p = maps[p][t];}return p == 2 || p == 3 || p == 7 || p == 8;} };思路二
用 bool 類型變量 ret 存儲(chǔ)搜索過程中的結(jié)果,整個(gè)搜索過程如下:
關(guān)于第8點(diǎn)檢查是否已經(jīng)遍歷完字符串:
因?yàn)槿绻址菙?shù)值,尾部空格應(yīng)該是字符串的末尾部分倒數(shù)幾個(gè)字符,空格完了字符串應(yīng)該也就結(jié)束了。如果過濾完了尾部空格還有字符,說明該字符串不是數(shù)值。
代碼二
class Solution { public:bool scanDigit(string s, int& i){int count = i;while(i != s.size()){if(isdigit(s[i]))++i;elsebreak;}return i > count;//如果數(shù)據(jù)中沒有一個(gè)數(shù)字,則直接返回false,有則返回true}bool scanSign(string s, int& i){if(i < s.size() && s[i] == '+' || s[i] == '-'){++i;}//過濾正負(fù)號(hào)return scanDigit(s, i);}bool isNumber(string s) {if(s.empty())return false;int i = 0;while(s[i] == ' ')++i;//過濾首部空格bool ret = scanSign(s, i);//第一遍搜索,先走完.或者e前的所有數(shù)字//.的后面可以有e,但e的后面不能有.,所以先處理.再處理eif(i < s.size() && s[i] == '.'){ret = scanDigit(s, ++i) || ret;//.前面可以什么都沒有,后面也可以什么都沒有,只要有一邊有數(shù)據(jù)就行}if(i < s.size() && (s[i] == 'e' || s[i] == 'E')){ret = scanSign(s, ++i) && ret;//e的前后必須都要有數(shù)據(jù),并且e后面可以存在正負(fù)號(hào),所以需要過濾正負(fù)號(hào)}while(s[i] == ' ')++i;//因?yàn)榭崭裰荒艹霈F(xiàn)在末尾和首部,過濾空格return ret && (i == s.size());//當(dāng)e后面有數(shù)據(jù),并且字符串全部走完,說明數(shù)據(jù)成立} };總結(jié)
以上是生活随笔為你收集整理的表示数值的字符串(有限状态自动机与搜索)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信用卡年费逾期后影响贷款吗?会有这些后果
- 下一篇: 一学就废的并查集它来了