最后一個字符——奇虎360筆試題


題目描述:(題目鏈接:最后一個字符

正在挑戰一個CrackMe的你,把需要填寫的前面幾位密碼都正確猜出了,可是這最后一位密碼,好像藏得有點深。CrackMe的作者還挑釁般的在里面藏了個.tar.gz文件,解壓縮出來,里面寫道
你要的最后一個字符就在下面這個字符串里,這個字符是下面整個字符串中第一個只出現一次的字符。(比如,串是abaccdeff,那么正確字符就是b了) 然而下面給出來的字符串好像太長太長了,單靠人力完全無法找出來。
於是,你需要寫一個程序代勞了。輸入文件體積較大,請使用一些快速的輸入輸出手段,不推薦使用cin/cout,對Java並不推薦使用Scanner直接讀寫。
 

輸入描述:
第一行,一個正整數T(T≤20)  ,表示輸入數據組數。
之后T行,每行一個字符串S。( 1≤S 的長度≤1000000 ,保證字符串中出現的字符的ASCII碼在[0x21,0x7F)范圍內,即均為可顯示的非空白符,同時保證一定有解)


輸出描述:
一共T 行,每行一個字符C ,表示所給的相應字符串中第一個只出現一次的字符。

輸入例子:
2
abaccdeff
testonline

輸出例子:
b
s
分析: 這題考察“字符串中第一個只出現一次的字符”這樣一個問題。這題《劍指offer》里面試題35給出了詳盡地分析及解答。我結合自己的思考總結一下。

首先最直觀的想法就是就是遍歷法,也就是從頭開始取字符串中的一個字符,將其與其后的所有字符比較,如果有相同的字符,那么就證明它不是只出現一次的字符。當第一次出現遍歷完其后字符並且沒有重復時,表明這個字符就是“第一個只出現一次的字符”。如果字符串有n個字符,每個字符可能與后面的O(n)個字符相比較,因此這種思路的時間復雜度是O(n2)。顯然復雜度很高,不滿意。需要改進一下。(代碼略)

換個角度考慮,由於要求第一個只出現一次的字符,那么就跟字符出現的次數有關。我們考慮如何統計字符出現的次數,然后找出第一個次數為1的那個字符。這里我們需要一個數據容器來保存字符出現次數,並且能夠通過字符找出其相對應的次數。我這里使用了關聯容器map。將字符串中出現過的字符作為鍵值,而值(Value)則是該字符出現的次數。這樣做會存在一個問題,就是我們無法知道出現次數為1的字符中哪一個是原字符串第一個出現的(關聯容器會對插入的元素自動進行排序)。因而需要另外建立一個容器,用來記錄原字符串中最先出現次數為1的字符。

有了這樣的思路之后,代碼如下:

#include<iostream>
#include<string>
#include<vector>
#include<map>

using namespace std;

int findfirstpos(string s,char ch)
{
int res = 0;
for(int i = 0;i<s.length();++i)
if(ch == s[i]){
res = i;
break;
}
return res;
}

int main()
{
int n;
while(cin>>n)
{
string str;
vector<string> vs;
for(int i = 0;i<n;++i)
{
cin>>str;
vs.push_back(str);
}
vector<map<char,int>> vm;
for(int i = 0;i<vs.size();++i)
{
map<char,int> mch;
for(int j = 0;j<vs[i].length();++j)
++mch[vs[i][j]]; //記錄每個鍵值出現的次數
vm.push_back(mch);
}
vector<vector<int>> vvpos;
for(int i = 0;i<vm.size();++i)
{
vector<int> tmpos;
for(auto it = vm[i].begin();it!=vm[i].end();++it)
if(it->second==1) //出現次數為1的鍵值對應的字符記錄下來
tmpos.push_back(findfirstpos(vs[i],it->first));
vvpos.push_back(tmpos);
tmpos.clear();
}
vector<int> vres;
for(int i = 0;i<vvpos.size();++i)
{
int min = 1000001;
for(int j = 0;j<vvpos[i].size();++j)
if(min>vvpos[i][j])
min = vvpos[i][j]; //將出現次數為1的字符中首次出現的字符記錄下來
vres.push_back(min);
}
for(int i = 0;i<vres.size();++i)
cout<<vs[i][vres[i]]<<endl;
vs.clear();
vm.clear();
vvpos.clear();
vres.clear();
}

return 0;
}

當然自己的這種方法可能不夠優化,因為可以使用hash表來進行存儲。具體分析可以參考博客面試題35:第一個只出現一次的字符


參考資料

第一個只出現一次的字符

輸出一串字符中第一個只出現一次的字符/不能使用while/for循環


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com