日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

表示数值的字符串(有限状态自动机与搜索)

發布時間:2023/12/13 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 表示数值的字符串(有限状态自动机与搜索) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 題目
  • 思路一
  • 代碼一
  • 思路二
  • 代碼二


題目



思路一

考察有限狀態自動機(參考jyd):

字符類型:

空格 「 」、數字「 0—9 」 、正負號 「 ± 」 、小數點 「 . 」 、冪符號 「 eE 」 。

狀態定義:

按照字符串從左到右的順序,定義以下 9 種狀態:

  • 開始的空格
  • 冪符號前的正負號
  • 小數點前的數字
  • 小數點、小數點后的數字
  • 當小數點前為空格時,小數點、小數點后的數字
  • 冪符號
  • 冪符號后的正負號
  • 冪符號后的數字
  • 結尾的空格
  • 結束狀態:

    合法的結束狀態有 2, 3, 7, 8 。

    算法流程:

  • 初始化:

  • 狀態轉移表 maps : 設 maps[i] ,其中 i 為所處狀態(9種之一), maps[i] 使用哈希表存儲可轉移至的狀態。鍵值對 (key, value) 含義:若此時的字符是 key ,則可從狀態 i 轉移至狀態 value 。
  • 當前狀態 p : 起始狀態初始化為 p = 0 。
  • 狀態轉移循環: 遍歷字符串 s 的每個字符 c 。

  • 記錄字符類型 t : 分為四種情況。

    • 當 c 為正負號時,執行 t = 's' ;
    • 當 c 為數字時,執行 t = 'd' ;
    • 當 c 為 e , E 時,執行 t = 'e' ;
    • 當 c 為 . , 空格 時,執行 t = c (即用字符本身表示字符類型);
    • 否則,執行 t = ‘?’ ,代表為不屬于判斷范圍的非法字符,后續直接返回 false。
  • 終止條件: 若字符類型 t 不在哈希表 maps[p] 中,說明無法轉移至下一狀態,因此直接返回 False 。

  • 狀態轉移: 狀態 p 轉移至 maps[p][t] 。

  • 返回值: 跳出循環后,若狀態 p∈2,3,7,8 ,說明結尾合法,返回 True ,否則返回 False 。

  • 再詳細說一下狀態轉移表的作用(下面代碼部分的注釋中有結合實例進行詳解):

    • 處于第 i 行表明此時遍歷到的字符是第 i+1 種狀態(可以對照上文的狀態定義)
    • 那么我下一個字符可以是第 i 行中的各個 key 對應的字符。
    • 如果某字符沒有寫進第 i 行,表示 i+1 狀態的下一個字符不應是某字符

    復雜度分析:

  • 時間復雜度 O(N) : 其中 N 為字符串 s 的長度,判斷需遍歷字符串,每輪狀態轉移的使用 O(1) 時間。
  • 空間復雜度 O(1) : maps 和 p 使用常數大小的額外空間。
  • 代碼一

    class Solution { public:bool isNumber(string s) {vector<map<char,int>> maps = { // 狀態轉移表 // 以第一行為例,狀態轉移表的含義為: // 開始的空格其下一個字符可以繼續是空格,也可以是符號、數字、小數點, // 但不可是第0行不存在的e。 // 也就是為了保證字符串是數值,空格后面不能直接跟一個冪符號。{{' ', 0}, {'s', 1}, {'d', 2}, {'.', 4}}, // 開始的空格{{'d', 2}, {'.', 4}}, // 冪符號前的正負號{{'d', 2}, {'.', 3}, {'e', 5}, {' ', 8}}, // 小數點前的數字{{'d', 3}, {'e', 5}, {' ', 8}}, // 小數點、小數點后的數字{{'d', 3}}, // 當小數點前為空格時,小數點、小數點后的數字{{'s', 6}, {'d', 7}}, // 冪符號{{'d', 7}}, // 冪符號后的正負號{{'d', 7}, {' ', 8}}, // 冪符號后的數字{{' ', 8}} // 結尾的空格};int p = 0; //起始狀態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 存儲搜索過程中的結果,整個搜索過程如下:

  • 過濾首部空格
  • 過濾正負號,緊接著檢查是否有數字
  • 遇到第一個不是數字的字符,應為 '.' 或者 e
  • '.' 的后面可以有 e,但 e 的后面不能有 '.' ,所以先處理 '.' 再處理 e
  • '.' 前面可以什么都沒有,后面也可以什么都沒有,只要有一邊有數據就行
  • e 的前后必須都要有數據,并且后面可以存在正負號,所以需要過濾正負號
  • 過濾尾部空格
  • 檢查 ret 狀態以及是否已經遍歷完字符串
  • 關于第8點檢查是否已經遍歷完字符串:

    因為如果字符串是數值,尾部空格應該是字符串的末尾部分倒數幾個字符,空格完了字符串應該也就結束了。如果過濾完了尾部空格還有字符,說明該字符串不是數值。

    代碼二

    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;//如果數據中沒有一個數字,則直接返回false,有則返回true}bool scanSign(string s, int& i){if(i < s.size() && s[i] == '+' || s[i] == '-'){++i;}//過濾正負號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前的所有數字//.的后面可以有e,但e的后面不能有.,所以先處理.再處理eif(i < s.size() && s[i] == '.'){ret = scanDigit(s, ++i) || ret;//.前面可以什么都沒有,后面也可以什么都沒有,只要有一邊有數據就行}if(i < s.size() && (s[i] == 'e' || s[i] == 'E')){ret = scanSign(s, ++i) && ret;//e的前后必須都要有數據,并且e后面可以存在正負號,所以需要過濾正負號}while(s[i] == ' ')++i;//因為空格只能出現在末尾和首部,過濾空格return ret && (i == s.size());//當e后面有數據,并且字符串全部走完,說明數據成立} };

    總結

    以上是生活随笔為你收集整理的表示数值的字符串(有限状态自动机与搜索)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。