今天下午参加民生银行总行的笔试,最后一个题是一个小的算法题。
题目:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。并且要求是用两种方法。
在网上搜索了一下,网上说这是2006年google的面试题。
方法1:
最简单,容易想到的就是双循环的那种,从前往后进行遍历,这种的复杂度是O(n^2)
简单的C++代码如下:
bool method1(
const
string& s,
char& c){
int len=s.size();
int i;
vector<
bool> flag(len);
for(
int i=
0;i<len;i++)
flag[i]=
true;
for(i=
0;i<len-
1;i++){
if(flag[i]){
int j;
for(j=i+
1;j<len;j++){
if(s[j]==s[i]) {
flag[j]=
false;
break;
}
}
if(j==len) {
c=s[i];
return
true;
}
}
flag[i]=
false;
}
if(i==len-
1)
return
false;
}
这儿需要注意的是需要用一个数组记录哪个字符已经出现过,这个非常重要,不然,如果前面已经出现过而后面没有出现过的字符有可能错认为是第一次出现。
比如,对于字符串”afadrrwsof“,如果不记录哪个字符出现过的话,会错认为第二个a是第一次出现
方法二:
因为是字符串,所以共有256个字符,可以使用一个256大小的数组来记录字符出现的个数。
其实这个方法很简单的。但是我想的有点复杂了,我想同时用一个数组记录256个字符第一次出现的位置,然后从第一次出现的字符中找到最先出现的字符。其实没有必要,只需要再将字符串扫描一遍就可以了,方法三就是这样实现的。
bool method2(
string& s,
char& c){
const
int N=
256;
int pos[N];
int count[N];
for(
int i=
0;i<N;i++){
pos[i]=-
1;
count[i]=
0;
}
int len=s.size();
for(
int i=
0;i<len;i++){
int t=static_cast<
int>(s[i]);
if(pos[t]==-
1){
pos[t]=i;
}
count[t]++;
}
int minp=len;
int position=-
1;
for(
int i=
0;i<N;i++){
if(count[i]==
1&&minp>pos[i]){
position=i;
minp=pos[i];
}
}
if(position!=-
1){
c=s[minp];
return
true;
}
else
return
false;
}
方法三:
bool method3(
const
string& s,
char& c){
const
int N=
256;
int len=s.size();
int count[N];
for(
int i=
0;i<N;i++)
count[i]=
0;
for(
int i=
0;i<len;i++) {
int t=static_cast<
int>(s[i]);
count[t]++;
}
for(
int i=
0;i<len;i++){
int t=static_cast<
int>(s[i]);
if(count[t]==
1)
{
c=s[i];
return
true;
}
}
return
false;
}
下面是对三个方法进行测试: 主要是随机生成30个字符串,对这些字符串进行测试。
int main(){
const
string alpha=
"
abcdefghigklmnopqrstuvwxyz
";
const
int n=
10;
string s(n,
'
');
for(
int j=
0;j<
30;j++) {
for(
int i=
0;i<n;i++) {
int pos=rand()%
26;
s[i]=alpha[pos];
}
char c1=-
1,c2=-
1,c3=-
1;
cout<<
"
s=
"<<s<<
"
";
method1(s,c1);
cout<<c1<<
"
";
method2(s,c2);
cout<<c2<<
"
";
method3(s,c3);
cout<<c3<<
"
";
cout<<endl;
}
}
下面是运行的结果: