這是曾經的一個面試題,正好引出狀態機編程思想。挺不錯的一個例子。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