雜湊表--面試題50-I、-II
技術標籤:劍指offer
文章目錄
面試題50-I 第一個只出現一次的字元
在字串 s 中找出第一個只出現一次
的字元
。如果沒有,返回一個單空格。
示例:
s = "abaccdeff"
返回 "b"
s = ""
返回 " "
題解:
模式識別:
涉及次數要考慮用雜湊表,一般字元為key,下標為值(或依據題意為其它)。
具體步驟:
程式碼:
class Solution {
public:
char firstUniqChar (string s) {
map<char,int> hashmap;
for(char val:s){
if(hashmap.find(val)==hashmap.end()) hashmap[val]=1;
else hashmap[val]++;
}
for(char val:s){
if(hashmap[val]==1) return val;
}
return ' ';
}
};
時間複雜度 O(N)
面試題50-II 字元流中第一個不重複的字元
題目:
請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。
返回值描述:
如果當前字元流沒有存在出現一次的字元,返回#字元。
題解(雜湊+佇列):
題解:
具體參考這:參考
針對題目的描述,我們先提出兩個問題?
Q1. 給定一個字串(只不過這裡的字串是可變的),如果快速判斷一個字元是否存在於字串中,如果存在,也就是重複?
對於一道題,如果沒有思路,就要針對題目給自己問問題。然後針對問題,來考慮需要什麼樣的演算法或者資料結構。
A1:對於“重複問題”,慣性思維應該想到雜湊或者set。對於“字串問題”,大多會用到雜湊。因此一結合,應該可以想到,判斷一個字元是否重複,可以選擇用雜湊,在c++中,可以選擇用unordered_map<char, int>
A2:對於字元流,源源不斷的往池子中新增字元,然後還要返回第一個滿足什麼條件的字元,顯然設計到了“順序”,也就是先來的先服務,這種先進先出的資料結構不就是佇列嘛。因此,這裡可以用佇列。
假如你已經知道了要用hash 和 queue 這兩個資料結構,你可以試著自己想一想,接下來的演算法過程是怎麼樣的?
這裡我提供一個演算法過程,如下:
1、初始化一個unordered_map<char, int> mp, queue q
2、對於Insert(char ch)操作, 如果ch是第一次出現,則新增到q中,然後在mp中記錄一下次數,如果不是第一次出現,也就是重複了,那麼我們就沒必要新增到q中,但是還是需要在mp中更新一下次數,因為之後要根據次數來判斷是否重複。
3、對於FirstAppearingOnce()操作,我們直接判斷q的頭部,然後在mp中檢查一下,是否重複,如果沒有重複,那就是我們想要的資料。否則,如果重複了,那就應該彈出頭部,然後判斷下一個頭部是否滿足要求。
【因為佇列中儲存的 “不重複字元” 在一系列的流讀取操作後,隨時有可能改變狀態(變重複),所以,佇列中的字元不能直接輸出,要先進行一次重複判斷,如果發現隊頭字元已經重複了,就將它移出佇列並判斷新的隊頭,否則,輸出隊頭的值;
】
程式碼:
class Solution
{
public:
map<char, int> hashmap;
queue<int> q;
//Insert one char from stringstream
void Insert(char ch)//字元流肯定是要一個一個的輸入的,所以要有Insert()操作;
{
if(hashmap.find(ch)==hashmap.end()) q.push(ch);
hashmap[ch]++;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
while(!q.empty()){
char ch=q.front();
if(hashmap[ch]==1) return ch;
else q.pop();
}
return '#';
}
};
時間複雜度O(N):對於Insert(char ch)操作,為O(1), 對於FirstAppearingOnce()操作,為O(N),因為最壞情況下,佇列中存入一半的重複資料, 比如“abcdabcd”,佇列會存入“abcd”,並且彈出的時候都是重複的。
空間複雜度:O(N),建立了雜湊表和佇列