SJTU ACMOJ 1780 独特字符串个数(自己起的烂名)
1.题干
输入若干字符串,输出“不相同”字符串的个数
其中,如果两个字符串每个字母的数量都相同,则判定为相同
且保证输入字符串均为小写字符串
2.主要思路
1.字符串的表示形式
字母的顺序并不重要,只要知道一个字符串中各个字母有几个就好了
所以每个字符串用一个26位数组表示(letter【26】)
2.字符串们的组织形式
目前考虑使用链表将现有的字符串按照一定顺序串成链表
定义“大”的字符串:靠前的字母数量多(类比数字大小比较)
则对于每个字符串,按照顺序遍历链表,找到合适的位置则插入,发现相同的字符串则结束遍历
3.获得结果
最终计算链表长度即可
3.复杂度分析
最坏情况下,n个字符串将长度为n的链表遍历一遍,为O(
n
2
n^2
n2)
实际上由于对链表进行了排序,一般不会最坏情况
3.代码
#include<iostream>
#include <string>
using namespace std;
//字符串 数组储存各字母个数
struct mystr {
int letter[26];
};
int scmp(mystr* s1, mystr* s2) {
for (int i = 0; i < 26; i++) {
if (s1->letter[i] > s2->letter[i])return 1; // s1 > s2
else if(s1->letter[i] < s2->letter[i])return -1; //s1 < s2
}
return 0; //s1 == s2
}
// 结点 储存本节点的值和下一节点位置
struct Node {
mystr* cont;
Node* next;
Node* pre;
Node() {
cont = new mystr();
}
};
int main() {
int n;
string a;
Node* Fsentinal = new Node();
Node* Lsentinal = new Node();
//双头链表 两个哨兵
Fsentinal->next = Lsentinal;
Lsentinal->pre = Fsentinal;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a;
bool flag = 1; // inserted?
int l = a.length();
Node* cur = new Node();
for (int j = 0; j < l; j++) {
cur->cont->letter[a[j] - 'a']++;
}
Node* p = Fsentinal->next;
while (p != Lsentinal) {
int res = scmp(p->cont, cur->cont); //和当前结点比较大小
if (res > 0) { p = p->next; } //比当前结点小,往后插入
else if(res < 0){ //比当前结点大,插在当前结点前面
Node* q = p->pre;
q->next = cur;
cur->pre = q;
cur->next = p;
p->pre = cur;
flag = 0;
break;
}
else{
//等于当前结点 无需插入
flag = 0;
break;
}
}
if (flag) { // need insert 一直遍历到队伍末尾 说明是最小元素 插在尾结点前面
p = Lsentinal->pre;
p->next = cur;
cur->next = Lsentinal;
cur->pre = p;
Lsentinal->pre = cur;
}
}
int cnt = 0;
Node* ss = Fsentinal->next;
while (ss != Lsentinal) {
cnt++;
ss = ss->next;
}
cout << cnt;
}