思路
普通思路就是先看第一个元素,遍历字符串看看每个字符总共在字符串中出现的次数,但是这是一个时间复杂度O(N^2)的算法,牛客上面是肯定跑不过的,所以我们可以想到用什么东西可以达到记录字符出现次数时间复杂度有符合要求的呢?
分析:看到这道题时,有两种思路:
(1)最直观的想法是从头开始扫描这个字符串中的每个字符。当访问到某字符时拿这个字符和后面的每个字符相比较,如果在后面没有发现重复的字符,则该字符就是只出现一次的字符。如果字符串有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路时间复杂度是O(n^2)。博主在此不推荐
(2)由于题目与字符出现的次数有关,可以统计每个字符在该字符串中出现的次数,需要一个数据容器存放每个字符的出现次数,即这个容器的作用是:把一个字符映射成一个数字。不难联想到利用字符的ASCII码,在常用的数据容器中,哈希表可实现此用途。
由于字符(char)是一个长度为8的数据类型(1字节=8bit位),因此总共有2^8=256
种可能。创建一个长度为256的数组,每个字母根据其ASCII码值作为数组的下标对应数组的一个数字,而数组中存储的是每个字符出现的次数。这样就创建了一个大小为256,以字符ASCII码为键值的哈希表。(并不仅限于英文字符,因此要考虑256种可能,若还要考虑汉字,则采用UNICODE这种2字节存储,有2^16=65536种可能)。
时间复杂度、空间复杂度分析:
第1次扫描这个数组时,每碰到一个字符,在哈希表中找到对应的项并把出现的次数增加一次,若字符串长度为n,则第1次扫描的时间复杂度是O(n);这样在进行第二次扫描时,就能直接从哈希表中得到每个字符出现的次数了,根据数组下标读一个字符出现的次数时间复杂度为O(1),因此总时间复杂度仍是O(n)。同时我们需要一个包含256个字符的辅助数组,由于此数组的大小是常数,可认为这种算法的空间复杂度是O(1)。
#include<iostream>
using namespace std;
#include<string>
#include<assert.h>
char FindFirst(string str){
assert(str.size() > 0);
int hashtable[256] = { 0 };
int i = 0;
for ( i = 0; i < str.size(); i++){
hashtable[str[i]]++;
}
for (i = 0; i< str.size(); i++){
if (hashtable[str[i]] == 1){
return str[i];
}
}
return 0;
}
int main(){
string str = "qabcdfabcde";
char ret = FindFirst(str); //将整数0赋给char类型变量ret,就是把ascii码为0,赋给ret
cout << ret << endl;
system("pause");
return 0;
}
另附 C/C++ strlen(str)和str.length()和str.size()的区别
https://blog.csdn.net/m0_37714594/article/details/79950023
C/C++ assert用法
https://www.cnblogs.com/lvchaoshun/p/7816288.html
更好的做法,第一个只出现一次的字符
https://blog.csdn.net/zzran/article/details/8508175