《剑指Offer》面试题35:第一个只出现一次的字符
知识点
如果需要判断多个字符是不是在某个字符串里出现过或者统计多个字符在某个字符串中出现的次数,我们可以考虑基于数组创建一个简单的哈希表,这样可以用很小的空间消耗换来时间效率的提升。
题目描述
在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”,则输出‘b’。
解题思路
字符(char)是一个长度为8的数据类型,因此总共有256种可能。于是我们创建一个长度为256的数组,每个字母根据其ASCII码作为数组的下标对应数组的一个数字,而数组中存储的是每个字符出现的次数。这样我们就创建了一个大小为256,以字符ASCII码为键值的哈希表。
空间复杂度:O(N),时间复杂度:O(1)。
代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str;
while(getline(cin,str))
{
const int tSize = 256;
int table[tSize] = {0}; //哈希表用来保存各个字符出现次数
bool flag = false; //判断是否找到
for(int i=0; i<str.size(); i++)
{
++table[str[i]];
}
for(int i=0; i<str.size(); i++)
{
if(table[str[i]] == 1) //判断是否是第一个只出现一次的字符
{
cout << str[i] << endl;
flag = true;
break;
}
}
if(flag == false) //若未找到
cout << 'NULL' << endl;
}
return 0;
}
题目拓展
拓展1
题目描述
输入一个定长的字符串,其中字符没有顺序,字符可以重复。输出最后一个只出现一次的字符。如果字符的出现次数都大于1,则返回NULL。
代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str;
while(getline(cin,str))
{
const int tSize = 256;
int table[tSize] = {0}; //哈希表用来保存各个字符出现次数
bool flag = false; //判断是否找到
for(int i=0; i<str.size(); i++)
{
++table[str[i]];
}
for(int i=str.size()-1; i>=0; i--)
{
if(table[str[i]] == 1) //判断是否是最后一个只出现一次的字符
{
cout << str[i] << endl;
flag = true;
break;
}
}
if(flag == false) //若未找到
cout << 'NULL' << endl;
}
return 0;
}
拓展2
题目描述
输入两个字符串,从第一个字符串中删除在第二个字符串中出现过的所有字符。例如,从第一个字符串“We are students”中删除在第二个字符串“aeiou”中出现过的字符得到的结果是“W r stdnts”。
代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str1, str2;
getline(cin, str1);
getline(cin, str2); //输入两个字符串
int table[256] = { 0 }; //哈希表存放第二个字符串各个字符出现的次数
for (int i = 0; i < str2.size(); i++)
{
++table[str2[i]];
}
for (int i = 0; i < str1.size(); i++)
{
if (table[str1[i]] != 0) //若字符串1中字符已在字符串2中出现
{
str1.erase(str1.begin() + i); //将该字符删除
i--; //删除后字符串1的长度减1,注意下标变化
}
}
cout << str1 << endl;
system("pause");
return 0;
}
拓展3
题目描述
定义一个函数,删除字符串中所有重复出现的字符。例如输入“google”,删除重复的字符之后的结果是“gole”。
代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str;
getline(cin, str); //输入字符串
bool table[256] = { false }; //布尔型哈希表,false代表以ASCII码为下标的字符未出现过,否则出现过
for (int i = 0; i < str.size(); i++)
{
if (table[str[i]] == false) //若字符第一次出现,将相应下标的哈希表值置为true
{
table[str[i]] =true;
}
else //否则删除字符
{
str.erase(str.begin() + i);
i--;
}
}
cout << str << endl;
system("pause");
return 0;
}
拓展4
题目描述
写一个方法来判断两个字符串是否互为变位词。
注:如果构成两个字符串的字符完全相同,而对应字符所处的位置不同,则称这两个字符串互为变位词。如:"abbfcad"和"facbdab"互为变位词。
代码
#include<iostream>
#include<string>
using namespace std;
bool isBianwei(string str1, string str2)
{
bool flag = true;
int table[256] = { 0 }; //哈希表用来统计字符串中字符出现的次数
for (int i = 0; i<str1.size(); i++)
{
++table[str1[i]]; //扫描第一个字符串,为哈希表对应项的值加1
}
for (int j = 0; j<str2.size(); j++)
{
--table[str2[j]]; //扫描第二个字符串,为哈希表对应项的值减1
}
for (int k = 0; k<255; k++)
{
if (table[k] != 0) //若哈希表每项的值均为0,则互为变位词,否则不互为变位词
flag = false;
}
return flag;
}
int main()
{
string str1, str2;
getline(cin, str1);
getline(cin, str2);
bool result = isBianwei(str1, str2);
if (result)
cout << str1 << "和" << str2 << "互为变位词";
else
cout << str1 << "和" << str2 << "不互为变位词";
system("pause");
return 0;
}