題目:在字符串中找出第一個只出現一次的字符。如輸入"abaccdeff",則輸出'b'。要求時間複雜度爲O(n)。算法
最直觀的想法是從頭開始掃描這個字符串中的每一個字符。當訪問到某字符時拿這個字符和後面的每一個字符相比較,若是在後面沒有發現重複的字符,則該字符就是隻出現一次的字符。若是字符串有n個字符,每一個字符可能與後面的O(n)個字符相比較,所以這種思路的時間複雜度是O(n2),可是不知足要求。數組
爲了解決這個問題,咱們能夠定義一個哈希表(外部空間),其鍵值(Key)是字符,而值(Value)是該字符出現的次數。單元測試
同時咱們還須要從頭開始掃描字符串兩次:測試
(1)第一次掃描字符串時,每掃描到一個字符就在哈希表的對應項中把次數加1。(時間效率O(n))ui
(2)第二次掃描時,每掃描到一個字符就能從哈希表中獲得該字符出現的次數。這樣第一個只出現一次的字符就是符合要求的輸出。(時間效率O(n))google
這樣算起來,總的時間複雜度仍然是O(n),知足了題目要求,擦一擦汗,感嘆:這*裝得真有點技術!spa
裝完了B,開始將這個想法實現爲代碼:code
public static char FirstNotRepeatingChar(string str) { if(string.IsNullOrEmpty(str)) { return '\0'; } char[] array = str.ToCharArray(); const int size = 256; // 藉助數組來模擬哈希表,只用1K的空間消耗 uint[] hastTable = new uint[size]; // 初始化數組 for (int i = 0; i < size; i++) { hastTable[i] = 0; } for (int i = 0; i < array.Length; i++) { hastTable[array[i]]++; } for (int i = 0; i < array.Length; i++) { if (hastTable[array[i]] == 1) { return array[i]; } } return '\0'; }
PS:字符(char)是一個長度爲8的數據類型,所以總共有256種可能。(在C#中char則是長度爲16位也就是2個字節)這裏咱們只列舉char是1個字節的狀況,咱們建立一個長度爲256的數組來模擬哈希表,每一個字母根據其ASCII碼值做爲數組的下標對應數組的一個數字,而數組中存儲的是每一個字符出現的次數。計算下來,它的大小是256*4字節(1個int類型在Windows下佔4個字節)=1K。因爲這個數組的大小是個常數,所以能夠認爲這種算法的空間複雜度是O(1)。 blog
// 常規輸入測試,存在只出現一次的字符 [TestMethod] public void FirstCharTest1() { char actual = CharHelper.FirstNotRepeatingChar("google"); Assert.AreEqual(actual, 'l'); } // 常規輸入測試,不存在只出現一次的字符 [TestMethod] public void FirstCharTest2() { char actual = CharHelper.FirstNotRepeatingChar("aabccdbd"); Assert.AreEqual(actual, '\0'); } // 常規輸入測試,全部字符都只出現一次 [TestMethod] public void FirstCharTest3() { char actual = CharHelper.FirstNotRepeatingChar("abcdefg"); Assert.AreEqual(actual, 'a'); } // 魯棒性測試,輸入NULL [TestMethod] public void FirstCharTest4() { char actual = CharHelper.FirstNotRepeatingChar(null); Assert.AreEqual(actual, '\0'); }
(1)測試經過狀況字符串
(2)代碼覆蓋率
若是須要判斷多個字符是否是在某個字符串裏出現過或者統計多個字符在某個字符串中出現的次數,咱們均可以考慮基於數組建立一個簡單的哈希表(或者使用基類庫中提供的現成的哈希表結構類型)。這樣能夠用很小的空間消耗換來換取時間效率的提高。