题目:
找出字符串第一个只出现一次的字符
解决思路:
我们可以通过遍历字符串,并统计相同元素的出现次数,取最小的一个。但是这样我们的时间复杂度为O(n^2)。
(1)本文介绍“以空间换时间”的思想实现O(n)的算法;
(2)创建一个哈希表,以每个字符ASCII码值为下标,相应内容为该字符的出现次数的哈希表,同时,一个字符有8个bit位,所以ASCII码可能是0-256,所以我们要创建的哈希表长度应为256;
(3)遍历字符串,将每个出现的字符次数填入到哈希表中;
(4)最后,遍历哈希表,找出出现次数最小的字符,将下标即ascii码转换即可输出。
还有许多要注意的点,我都注释在了代码中。
实现代码:
#include <stdio.h>
#define MAXSIZE 256
int flag = 0;//用来标记函数出错返回的情况
typedef size_t(*HashFunc)(int key);
typedef enum
{
Empty,//当前位置为空
Valid,//当前位置有效
}Stat;
typedef struct HashElem
{
char key;//字符的ASCII码值即下标
int value;//字符对应的出现次数
Stat stat;//当前位置的状态,是否有效
size_t size;//标记该字符第一次出现的在原字符串中的位置
}HashElem;
typedef struct Hash
{
HashFunc func;//函数指针,用来传入判断存储位置的函数
HashElem data[MAXSIZE];
}Hash;
size_t HashFuncDefault(int key)//用来计算存储位置的函数
{
return key % MAXSIZE;
}
void EnterHash(Hash* hash, char arr[], int len, HashFunc func)
{
int i = 0;
if (arr == NULL || hash == NULL)
return;
hash->func = func;//哈希表初始化
for (; i < MAXSIZE; ++i)
hash->data[i].stat = Empty;
for (i = 0; i < len; ++i)//遍历数组,存入哈希表
{
size_t offset = hash->func(arr[i]);
if (hash->data[offset].stat == Empty)//当当前字符是第一次向哈希表中存
{
hash->data[offset].value = 1;
hash->data[offset].key = arr[i];
hash->data[offset].stat = Valid;
hash->data[offset].size = i;
}
else//当前字符已在哈希表中了
hash->data[offset].value += 1;
}
}
char FindOneTimeNum(Hash* hash)
{
int ret = 0;//用来标记第一个不为空的元素
size_t i = 0;
int num = -1;//用来比较存放最先在字符串中出现的字符,因为哈希表中存是按照ascii码而不是先后出现顺序
if (hash == NULL)
{
flag = -1;
return 'X';
}
for (i = 0; i < MAXSIZE; ++i)
{
if (hash->data[i].stat == Valid && hash->data[i].value == 1)//当前字符仅在字符串中出现了一次
{
if (ret == 0)//num还未记录的有仅出现一次的字符
{
num = i;
ret = 1;
}
else
{
if (hash->data[num].size > hash->data[i].size)//当前字符比num记录的字符更先出现在字符串
num = i;
}
}
}
if (num == -1)
return 'X';
return hash->data[num].key;
}
int main()
{
char arr[] = "acuiasoasb";
int size = sizeof(arr) / sizeof(arr[0]) - 1;
Hash hash;
char ret;
EnterHash(&hash, arr, size, HashFuncDefault);
ret = FindOneTimeNum(&hash);
if (ret == 'X')
{
if (flag == -1)
printf("参数error\n");
else
printf("return 0\n");
}
else
printf("expected is c, actual is %c\n", ret);
system("pause");
return 0;
}