1. 程式人生 > >劍指Offer面試題:30.第一個只出現一次的字元

劍指Offer面試題:30.第一個只出現一次的字元

一、題目:第一個只出現一次的字元

題目:在字串中找出第一個只出現一次的字元。如輸入"abaccdeff",則輸出'b'。要求時間複雜度為O(n)

  最直觀的想法是從頭開始掃描這個字串中的每個字元。當訪問到某字元時拿這個字元和後面的每個字元相比較,如果在後面沒有發現重複的字元,則該字元就是隻出現一次的字元。如果字串有n個字元,每個字元可能與後面的O(n)個字元相比較,因此這種思路的時間複雜度是O(n2),但是不滿足要求。

二、解題思路:以空間換時間

   為了解決這個問題,我們可以定義一個雜湊表(外部空間),其鍵值(Key)是字元,而值(Value)是該字元出現的次數。

  同時我們還需要從頭開始掃描字串兩次:

  (1)第一次掃描字串時,每掃描到一個字元就在雜湊表的對應項中把次數加1。(時間效率O(n))

  (2)第二次掃描時,每掃描到一個字元就能從雜湊表中得到該字元出現的次數。這樣第一個只出現一次的字元就是符合要求的輸出。(時間效率O(n))

  這樣算起來,總的時間複雜度仍然是O(n),滿足了題目要求,擦一擦汗,感嘆:這*裝得真有點技術!

  裝完了B,開始將這個想法實現為程式碼:

    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)。 

三、單元測試

3.1 測試用例

    // 常規輸入測試,存在只出現一次的字元
    [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');
    }

3.2 測試結果

  (1)測試通過情況

  (2)程式碼覆蓋率

四、總結擴充套件

  如果需要判斷多個字元是不是在某個字串裡出現過或者統計多個字元在某個字串中出現的次數,我們都可以考慮基於陣列建立一個簡單的雜湊表(或者使用基類庫中提供的現成的雜湊表結構型別)。這樣可以用很小的空間消耗換來換取時間效率的提升。

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

Offer試題30.第一出現字元

一、題目:第一個只出現一次的字元 題目:在字串中找出第一個只出現一次的字元。如輸入"abaccdeff",則輸出'b'。要求時間複雜度為O(n)。   最直觀的想法是從頭開始掃描這個字串中的每個字元。當訪問到某字元時拿這個字元和後面的每個字元相比較,如果在後面沒有發現重複的字元,則該字元就是隻出現

offer--找出字串中第一出現字元(題已經更新)C++

題目描述: 找出字串中第一個只出現一次的字元 輸入描述: 輸入一個非空字串 輸出描述: 輸出第一個只出現一次的字元,如果不存在輸出-1 示例1 輸入 asdfasdfo 輸出 ö 程式碼實現如下: #include<iostream>

Offer試題31.兩連結串列的第一公共節點

一、題目:兩個連結串列的第一個公共節點 題目:輸入兩個連結串列,找出它們的第一個公共結點。   連結串列結點定義如下,這裡使用C#語言描述: public class Node { public int key; public Node

【LeetCode & offer刷題】字串題150 第一出現字元(387. First Unique Character in a String)

【LeetCode & 劍指offer 刷題筆記】目錄(持續更新中...) 387. First Unique Character in a String Given a string, find the first non-repeati

第一出現字元的位置 牛客網 Offer

第一個只出現一次字元的位置  牛客網 劍指Offer 題目描述 在一個字串(0<=字串長度<=10000,全部由字母組成)中找到第一個只出現一次的字元,並返回它的位置, 如果沒有則返回

試題數組中出現的數字

new ++ array ear style 哈希表 else 兩個 個數 題目描述:一個整型數組裏除了兩個數字之外,其他的數字都出現了偶數次。請寫程序找出這兩個只出現一次的數字。 方法1:哈希表 //num1,num2分別為長度為1的數組。傳出參數 //將num1[0]

offer:(40)知識遷移 :陣列中出現的數字

一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。 思路:    可以用位運算實現,如果將所有所有數字相異或,則最後的結果肯定是那兩個只出現一次的數字異或 的結果,所以根據異或的結果1所在的最低位,把數字分成兩半,每一半

offer 試題50字元流中第一出現字元

題目描述:請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。 解法: 使用雜湊表occurance[256] ;  初始化o

offer 試題50字元流中第一出現字元

題目描述:請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。 解法: 使用雜湊表occurance[256] ;

Offer試題35(java版)第一出現字元

題目:在字串中找出第一個只出現一次的字元。如輸入"abaccdeff",則輸出'b'. 看到這樣的題目,我們最直觀的想法就是從頭開始掃描這個字串中的字元。當訪問某個字元時拿這個字元和後面的每個字元相比

offer試題50字元流中)第一出現字元【C++版本】

題目:字串中第一個只出現一次的字元。 在字串中找出第一個只出現一次的字元。如輸入"abaccdeff" "abaccdeff",則輸出′ b ′  ′b′。 解題思路: 1.使用雜湊表來記錄每個字元出現的次數,因為字元char char為8位,

牛客網線上程式設計專題《offer-試題37》兩連結串列的第一公共結點

題目連結: 題目描述: 解題思路: 首先遍歷兩個連結串列得到它們的長度,就能知道哪個連結串列比較長,以及長的連結串列比短的連結串列多幾個結點。在第二次遍歷的時候,在較長的連結串列上先走若干步,接著再同時在兩個連結串列上遍歷,找到的第一個相同的結點就是它們的第

offer 試題重建二叉樹

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。 思路:二叉樹先序是根左右,中序 是左根右。所以先找到

offer 試題從尾到頭列印連結串列

題目:輸入一個連結串列,按連結串列值從尾到頭的順序返回一個ArrayList。 思路:有多種放法。(1)先反轉連結串列,再列印連結串列。(2)使用棧。 /** * struct ListNode { * int val; * struct ListNode *n

Offer試題17.樹的子結構

一、題目:樹的子結構 題目:輸入兩棵二叉樹A和B,判斷B是不是A的子結構。例如下圖中的兩棵二叉樹,由於A中有一部分子樹的結構和B是一樣的,因此B是A的子結構。   該二叉樹的節點定義如下,這裡使用C#語言描述: public class BinaryTreeNode {

Offer試題2.二維陣列中的查詢

一、題目:二維陣列中的查詢 題目:在一個二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。     例如下面的二維陣列就是每行、每列都遞增排序。如果在這個陣列中查詢數字7,則返回true;

Offer試題22.二叉搜尋樹的後序遍歷序列

一、題目:二叉搜尋樹的後序遍歷序列 題目:輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則返回true,否則返回false。假設輸入的陣列的任意兩個數字都互不相同。   例如在下面的一顆二叉搜尋樹中,輸入陣列{5,7,6,9,11,10,8},則返回true,因為這個整數序列是

Offer試題14.連結串列的倒數第k節點

PS:這是一道出境率極高的題目,記得去年參加校園招聘時我看到了3次,但是每次寫的都不完善。 一、題目:連結串列的倒數第k個節點 題目:輸入一個連結串列,輸出該連結串列中倒數第k個結點。為了符合大多數人的習慣,本題從1開始計數,即連結串列的尾結點是倒數第1個結點。例如一個連結串列有6個結點,從頭結點開始

Offer試題28.連續子陣列的最大和

一、題目:連續子陣列的最大和 題目:輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。例如輸入的陣列為{1,-2,3,10,-4,7,2,-5},和最大的子陣列為{3,10,-4,7,2},因此輸出為該子陣列的和18。

Offer試題4.從尾到頭列印連結串列

一、題目:從尾到頭列印連結串列 題目:輸入一個連結串列的頭結點,從尾到頭反過來打印出每個結點的值。   到解決這個問題肯定要遍歷連結串列。遍歷的順序是從頭到尾的順序,可輸出的順序卻是從尾到頭。也就是說第一個遍歷到的結點最後一個輸出,而最後一個遍歷到的結點第一個輸出。這就是典型的“後進先出”,我