面试题50:第一个只出现一次的字符
题目描述(1)字符串中第一个只出现一次的字符
在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”,则输出‘b’。并返回它的位置, 如果没有则返回 -1(需要区分大小写)。
思路
在字符串中查找某个字符——查找
查找算法:顺序查找、二分查找、二叉排序树查找、哈希表查找
二分查找和二叉排序树,针对有序的数组
1.使用顺序查找:
从头到尾依次取字符,遍历后面的字符与取出的字符比较,若无相同的字符则返回这个字符,否则取下一个字符重复上述过程。时间复杂度为O(n2)
2.哈希表查找:
把字符作为键,遍历字符串,字符的个数作为值。产生哈希表。再按照字符串的顺序从头到尾开始查找第一个值为1的键。
基于数组创建哈希表
键值是字符,char的取值范围较小(0-255),所以可以直接开一个大小为256的数组,以数组下标作为键值(字符ASCII码)。当键值范围较大时(如unicode),不适合用数组创建哈希表。
int FirstNotRepeatingChar(string str) {
//0.特殊
auto len = str.size();
if(len == 0)
return -1;
//1.初始化基于数组的哈希表
int hashTable[256] = {0};
//2.构建哈希表
for(int i = 0; i<len; ++i){
++hashTable[str[i]];
}
//3.哈希表查找
for(int i = 0; i<len; ++i){
if(hashTable[str[i]] == 1)
return i;
}
return -1;
}
基于STL中unordered_map创建哈希表
关联容器:按关键字来保存和访问。
顺序容器:按元素的位置顺序保存和访问。
类型 | 含义 |
---|---|
map | 关联数组 保存键-值对(按顺序) |
multimap | 关键字可重复出现的map |
unordered_map | 用哈希函数组值的map (不按顺序) |
unordered_multimap | 哈希组值的map,关键字可重复 |
map和unordered_map支持下标和at函数。
下标操作的返回值是左值,既可读也可写。
int FirstNotRepeatingChar(string str) {
//1.定义哈希表
unordered_map<char, size_t> char_count;
//2.构建哈希表
for(auto a: str)
{
++char_count[a];//没有数组越界问题,若a不再map中,将插入这个元素
}
//3.哈希表查找
for(int i = 0; i<str.size(); ++i){
if(char_count[str[i]]== 1)//使用str[i]来遍历 按顺序 用map的迭代器不是按照字符串的顺序
return i;
}
return -1;
}
题目描述(2)
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
思路
每插入一个字符,哈希表记录字符位置(第一次出现),或设置特殊值(多次出现)。最后遍历哈希表,查找最小值(最先出现),它对应的键即字符的ASCII码。
class Solution
{
public:
/*Solution():index(1){
for(int i = 0; i<256; ++i){
hashTable[i] = 0;
}
}*/
//Insert one char from stringstream
void Insert(char ch)
{
if(hashTable[ch] == 0){
hashTable[ch] = index;//错误:=写成 ==
}
else if(hashTable[ch] > 0){
hashTable[ch] = -1;
}
++index;
}
//return the first appearence once char in current stringstream
char FirstAppearingOnce()
{
int minIndex = 100;//numeric_limits<int>::max();
char ch = '\0';
for(int i = 0; i<256; ++i){
if(hashTable[i] < minIndex && hashTable[i] >0){
minIndex = hashTable[i];
ch = (char)i;
}
}
if(ch == '\0')
return '#';
return ch;
}
private:
int hashTable[256] = {0};
int index = 1;
};
Note
在使用数组下标时,通常将其定义为size_t类型。size_t是一种机器相关的无符号类型,它被设计得足够大以便能表示内存中任意对象的大小。