求好的算法,关于字符串分组的算法

就呆在云上 2012-05-06 09:38:49
现在有个郁闷的问题,就是没有好的算法。

问题描述:
我有60万个字符串,字符串都是由13个字符组成,每个字符都只可能是0、1、2之一,比如:
1201201201201

我现在要对这些字符串分组:最多一个字符不一样的两个字符串是一个分组,也就是说完全一样就是一组,仅仅有一个字符不一样也算是一个组的。

相同的组在相同的字符要求顺序一样的。简单点说,如果只考虑3个字符的话:012和011是一组,012和022也是一组。但是012和210就不是一组了,因为分组要求顺序一致。

分组呢,如果一个字符串发现自己和另一个字符串一组了,就不用和下一个再比较了。

直接用遍历的方式一个个太慢了,求好办法哈。

谢谢大家了。
...全文
475 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
ken_scott 2012-05-12
  • 打赏
  • 举报
回复
既然楼主不回复我的疑问,那我等下用自己的理解写一份
ken_scott 2012-05-12
  • 打赏
  • 举报
回复
如果是000 001 010 则分组为 {000, 001}, {010}
如果是000 010 001 则分组为 {000, 010}, {001}

如果楼主的题意与上面不同, 下面的请忽略...


#include <ctime>
#include <string>
#include <vector>
#include <list>
#include <iostream>
using namespace std;

const int ele_count = 10000;
const int chr_count = 13;

struct group
{
int id;
int diff_op;
list<int> index;
};

vector<string> strs;
list<group> grps;

string random_str()
{
static char c_range[] = { '0', '1', '2' };
string rand_str;

rand_str.resize(chr_count);
for (int i = 0; i < chr_count; ++i) {
rand_str[i] = c_range[rand() % 3];
}

return(rand_str);
}

void get_elements()
{
srand(time(NULL));
strs.resize(ele_count);
for (int i = 0; i < ele_count; ++i) {
strs[i] = random_str();
}
}

void get_groups()
{
typedef list<group>::iterator liter;
for (int i = 0; i < ele_count; ++i) {
const string & rstr = strs[i];
bool need_add_grp = true;

for (liter iter = grps.begin(); grps.end() != iter; ++iter) {
group & rgrps = (*iter);
const string & rfstr = strs[rgrps.index.front()];

if (rgrps.diff_op < 0) {
int diff_cnt = 0;
int diff_op = -1;

for (int j = 0; j < chr_count; ++j) {
if (rstr[j] != rfstr[j]) {
if (1 == ++diff_cnt) {
diff_op = j;
}
else {
break;
}
}
}

if (diff_cnt > 1) {
continue;
}

if (1 == diff_cnt) {
rgrps.diff_op = diff_op;
}
rgrps.index.push_back(i);
need_add_grp = false;
break;
}
else {
bool belong = true;
for (int j = 0; j < chr_count; ++j) {
if (j != rgrps.diff_op && rstr[j] != rfstr[j]) {
belong = false;
break;
}
}
if (belong) {
rgrps.index.push_back(i);
need_add_grp = false;
break;
}
}
}
if (need_add_grp) {
group ngrp;
ngrp.id = grps.size();
ngrp.diff_op = -1;
ngrp.index.push_back(i);
grps.push_back(ngrp);
}
}
}

void check()
{
int count = 0;
typedef list<group>::iterator liter;
for (liter iter = grps.begin(); grps.end() != iter; ++iter) {
const group & rgrp = (*iter);
count += rgrp.index.size();
// cout << rgrp.id << " " << rgrp.index.size() << endl;
}
cout << count << endl;
}

int main()
{
int start = time(NULL);
get_elements();
get_groups();
int finish = time(NULL);
cout << "use time: " << (finish - start) << "s" << endl;
check();
return(0);
}

字符有150多万(3^13)种可能, 远大于60万, 如果这些字符是随时的, 大多都是一个字符串一个组,
代码再怎么优化, 都会往最坏的情况(60万*60万)上跑, 我的代码60万跑不出来
赵4老师 2012-05-09
  • 打赏
  • 举报
回复
请先试试手动将6个4个字符长的字符串分组,弄清楚到底想要什么结果。
赵4老师 2012-05-09
  • 打赏
  • 举报
回复
不要写连自己也预测不了结果的代码!
孤独小剑 2012-05-09
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

引用 5 楼 的回复:

有个疑问:012和011是一组,012和022也是一组
那么011和022是一组吗?是先遇到现出现的建立一个分组?
012建立分组后遇到011以及022都被分到012的分组,而不管011和022是否为一个分组?

011 和 022 明显不是一个组(所有字符只有一个不一样才算一组,就是说与字符位置也是有关系的),一个新的字符串如果没有查找到分组则新建一个分组
[/Quote]问题是:011会和012一组,022会和012一组,事先一句012建立的分组,之后分别遇到011和022,011和022会不会同被分配到012的组?
muyi66 2012-05-08
  • 打赏
  • 举报
回复
我好像找到一种可以实现局部遍历的方法,编组效率应该可以提升一个数量级以上。但需要先做排序操作,可能会彻底破坏掉字串顺序,使得按新顺序编排的分组与按原顺序编排的分组不尽相同,但仍符合顶楼所说原则。

这样的做法是否可接受的?

呃,说“好像”的意思是考虑还不完全,不知道是否真正可行。
ken_scott 2012-05-08
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]
引用 5 楼 的回复:

有个疑问:012和011是一组,012和022也是一组
那么011和022是一组吗?是先遇到现出现的建立一个分组?
012建立分组后遇到011以及022都被分到012的分组,而不管011和022是否为一个分组?


011 和 022 明显不是一个组(所有字符只有一个不一样才算一组,就是说与字符位置也是有关系的),一个新的字符串如果没有查找到分组则新建一个分组
[/Quote]
我和5L有一样的疑问, 想问下000-222按你的分组, 结果会是怎么的?
就呆在云上 2012-05-08
  • 打赏
  • 举报
回复
如果简化一下要求,给一个60万字符串的文本,按照上面的要求,属于同一组的字符串只保留一个来输出一个文本,大家看有好的方法没,不是不让遍历,普通计算机VC 运行10分钟内能出结果就可以,已经有人提供了一个算法,我试验后再和大家一起研讨一下呵
W170532934 2012-05-08
  • 打赏
  • 举报
回复
只能遍历了。我觉得。
孤独小剑 2012-05-07
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

借助于字典树可好使,遍历一次就能搞掂,当遇到一个字符不一样的时候看下面是否全一样,就是这样有点占用内存
[/Quote] 内存占用也不大诶,最大也就10+M,一个结构占16个字节的话。
pathuang68 2012-05-07
  • 打赏
  • 举报
回复
个人认为字典树可能解决不了这个问题。
muyi66 2012-05-07
  • 打赏
  • 举报
回复
我没想出不需要遍历的做法,只想出加快比较速度的方法。而且随着分组进程,比较生成的键值会不断变化,想不出有什么好办法可以缩减遍历操作来。
就呆在云上 2012-05-07
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]

另外是否有空间限制?多用几十兆没问题吧?
[/Quote]

没有空间限制,VC 可以运行跑处结果就可以
muyi66 2012-05-07
  • 打赏
  • 举报
回复
另外是否有空间限制?多用几十兆没问题吧?
muyi66 2012-05-07
  • 打赏
  • 举报
回复
这个真有点难了,字典树不能提供足够的信息,哈西表根本无法完成任务。

能说说你的时间限制吗?需要在多长时间里完成它?
nice_cxf 2012-05-07
  • 打赏
  • 举报
回复
既然有一个不同算为1组,那么就把最后一位不用就是了,前12位做为hash的关键字保存,当然这样做分的组会多些,不知道是否符合你要求
Furney 2012-05-07
  • 打赏
  • 举报
回复
利用字典树可以避免有重复数据出现
大尾巴猫 2012-05-06
  • 打赏
  • 举报
回复
看错,以为是3个字符一组。没看到是13个字符一组的。上面这个办法不行了
大尾巴猫 2012-05-06
  • 打赏
  • 举报
回复
0,1,2 三进制,三位的话只有27种可能,用一个数组表示
先取3个字符,换算成三进制的数字,按照这个下标去数组查找,如果数组元素为0,说明未分组
就从头去匹配分组,如果成功分到组,该下表的数组元素记录组别号,如果没分到组,建立新组,并在数组中标记。这样下次再有同样的3个字符就不用重复找组了。一共27种组合方式,也就是说只有27次会从头匹配
比O(n平方)好很多吧。

不知道上面的思路对不对。
昵称很不好取 2012-05-06
  • 打赏
  • 举报
回复
借助于字典树可好使,遍历一次就能搞掂,当遇到一个字符不一样的时候看下面是否全一样,就是这样有点占用内存
加载更多回复(6)

64,282

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧