我编写了以下程序来回答这个问题
编写一个高效的函数来查找字符串中第一个不重复的字符。例如,“total”中第一个不重复的字符是“o”,“teeter”中第一个不重复的字符是“r”。讨论算法的效率。
这就是我所做的:
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
class Node
{
public:
Node::Node(char ch)
{
c = ch;
next = NULL;
}
char c;
Node *next;
};
Node* addNode(Node *tail, char ch)
{
if(tail == NULL)
return new Node(ch);
else
{
Node *newN = new Node(ch);
tail->next = newN;
return newN;
}
}
void deleteNode(char ch, Node** head, Node**tail)
{
Node *prev = NULL;
Node *cur = *head;
while(cur!=NULL)
{
if(cur->c == ch)
{
// found cut it
if(prev == NULL)
{
// head cut off
if(*tail == *head)
{
// worst possible, just one element
delete *head;
*head = NULL;
return;
}
else
{
// Head cut off but not just first element
Node *tmp = *head;
*head = (*head)->next;
delete tmp;
return;
}
}
else
{
// delete normal node
if(*tail == cur)
{
// delete tail
Node *tmp = *tail;
*tail = prev;
delete tmp;
return;
}
else
{
// Normal node not tail
prev->next = cur->next;
delete cur;
return;
}
}
}
// no match keep searching
prev = cur;
cur = cur->next;
}
}
int main()
{
char str[] = "total";
char htable[26];
memset(htable, 0, sizeof(char)*26);
Node *head = NULL;
Node *tail = head;
for(unsigned int i=0;;i++)
{
if(str[i] == '\0')
break;
// check first match
char m = htable[str[i]-'a'];
switch(m)
{
case 0:
{
// first time, add it to linked list
htable[str[i]-'a']++;
tail = addNode(tail, str[i]);
if(head == NULL)
head = tail;
}break;
case 1:
{
// bam, cut it out
htable[str[i]-'a']++;
deleteNode(str[i], &head, &tail);
}break;
}
}
if(head != NULL)
printf("First char without repetition: %c", head->c);
else
printf("No char matched");
return 0;
}
它可以工作(尽管我没有在程序结束时为链表释放内存)。基本上,如果还没有找到一个字符,我会保留一个带有 0 的哈希表,如果找到了一次(并且它被添加到链表的尾部位置)则为 1,如果至少出现两次,则为 2 (并且应该被链表删除)。
这个程序的大 O 表示法的计算复杂度是多少?
由于这个算法每个元素只通过一次,我认为它是 O(n),尽管删除链表中的值(在最坏的情况下可能)需要额外的 O(k^2),其中 k 是使用的字母表。像 O(n+k^2) 这样的东西是我的选择,如果字符串很长并且字母表受到限制,算法就会变得非常有效。