狀態機編程思想(1):括號內外字符串統計

這是曾經的一個面試題,正好引出狀態機編程思想。挺不錯的一個例子。html

題目描述

給定一個字符串,它由如下字符組成:面試

  • 左括號「(」
  • 右括號「)」
  • 下劃線「_」 
  • 大小寫字母構成的字符串(單字母也算做字符串)

該字符串組成有如下規則限定:編程

  • 括號成對出現且不會嵌套,保證語法正確
  • 字符串能夠出如今括號內,也能夠出如今括號外
  • 各個字符串之間必須用下劃線「_」隔開
  • 括號外的字符串必須如下劃線「_」爲邊界;括號內字符串的邊界能夠是下劃線「_」,也能夠是括號「(」、「)」

請解決問題:設計模式

  • 括號內字符串個數
  • 統計括號外最長字符串的長度

 傳統思路

咱們拿到這個問題時,第一感受每每是順序遍歷字符串,並檢測左右相鄰字符是否知足邊界條件,從而進行分支處理。可是這樣作有如下棘手之處:app

  • 斷定括號邊界時須要保存以前的狀態,而處理程序和斷定狀態邏輯每每混亂成一鍋粥,難解難分
  • 不一樣狀態下的處理邏輯不一樣,這樣對於大型問題,邏輯之間有可能產生耦合,甚至在不一樣狀態間跳來跳去
  • 還有效率問題,每次處理當前字符時還有同時處理左右相鄰字符,工做量有冗餘,效率下降

嗯,不信的話,能夠本身按照上述最簡單的思路實現一下,你就明白了。post

有人說,複雜邏輯我不怕啊,細心就好。So...是時候請出咱們的大俠--「狀態機」了。測試

狀態機思路

狀態機是編譯原理中的一種技術,學過電學的讀者應該也在《數字電子技術》中用過它,歸根結底,就是把複雜的問題邏輯化爲一個一個的狀態,咱們處理問題的過程就是在各個狀態之間不斷遷移(包含自遷移),這樣畫出來的圖就叫作狀態遷移圖,幫助咱們把一鍋難纏的粥轉化爲一張清晰的網。固然,這裏不會深究狀態機的概念,詳情請自查(好比還有狀態遷移表等等)。this

讓咱們用狀態遷移圖表示上面的問題(若看不清圖,能夠右鍵在新的標籤頁看,或者下載下來看):spa

 

我設置了兩個狀態,一個用來區分括號內外,一個用來區分是不是字母,從而進行不一樣的處理。設計

括號內外分紅了兩個子狀態,這兩個子狀態是互斥的,所以他們內部的狀態變量能夠共用。

至於狀態之間轉移條件,直接看代碼便可理解:

複製代碼
 1 public class CountWords {
 2 
 3     final static int InBracket = 0;// 括號內
 4     final static int OutBracket = 1;// 括號外
 5 
 6     final static int IsLetter = 0;// 是字母
 7     final static int NotLetter = 1;// 不是字母
 8 
 9     public static void main(String[] args) {
10         test("_yy_()()_(_apple_welcome)_ssjjjs_");//2,6
11         test("__()()_(_)__()_");//0,0
12         test("_ya_");//0,2
13         test("_yy_(_)(r)_(_wel_c_ome_k)_");//5,2
14         test("_yy_aa_");//0,2
15         test("_yy_(aaa_bb_c)()__yyyyy_");//3,5
16         test("(u)_()_(__)()_yy_()");//1,2
17         test("__(a_wwwww)");//2,0
18         test("__(_a_wwwww_)_____ddd____()()()()()()");//2,3
19     }
20 
21     public static void test(String str) {
22         // 狀態初始化
23         int state_INOUT = OutBracket;
24         int state_letter = NotLetter;
25         // 統計結果初始化
26         int outLengthOfLongestWord = 0;
27         int outLengthOfCurrentWord = 0;
28         int inNumsOfWord = 0;
29         // 開始處理
30         for (int i = 0; i < str.length(); ++i) {
31             // 取出當前字符
32             char c = str.charAt(i);
33             // 根據括號設置狀態:括號內、括號外
34             if (c == '(') {
35                 state_INOUT = InBracket;
36             }
37             if (c == ')') {
38                 state_INOUT = OutBracket;
39             }
40             // 括號內狀態
41             if (state_INOUT == InBracket) {
42                 if (state_letter == IsLetter) {
43                     if (c == '_' || c == ')') {
44                         state_letter = NotLetter;
45                     }
46                 } else if (state_letter == NotLetter) {
47                     if (Character.isLetter(c)) {
48                         state_letter = IsLetter;
49                         ++inNumsOfWord;
50                     }
51                 }
52             }
53             // 括號外狀態
54             else if (state_INOUT == OutBracket) {
55                 if (state_letter == IsLetter) {
56                     // System.out.println(c);
57                     if (c == '_' || c == '(') {
58                         if (outLengthOfLongestWord < outLengthOfCurrentWord) {
59                             outLengthOfLongestWord = outLengthOfCurrentWord;
60                         }
61                         outLengthOfCurrentWord = 0;
62                         state_letter = NotLetter;
63                     } else if (Character.isLetter(c)) {
64                         ++outLengthOfCurrentWord;
65                     }
66                 }
67                 if (state_letter == NotLetter) {
68                     if (Character.isLetter(c)) {
69                         state_letter = IsLetter;
70                         ++outLengthOfCurrentWord;
71                     }
72                 }
73             }
74         }
75         System.out.println("括號內的字符串數:" + inNumsOfWord);
76         System.out.println("括號外的最長字符串長度:" + outLengthOfLongestWord);
77         System.out.println();
78 
79     }
80 
81 }
複製代碼

有沒有感受到很方便?思路更清晰了,效率也上去了。

注:狀態機不一樣於設計模式中常說的狀態模式。

就這麼多吧,歡迎提出測試樣例找bug,共同進步。

 

出處:http://www.cnblogs.com/xiaoxi666/p/7929347.html

相關文章
相關標籤/搜索