求一个字符串中各个子串出现的次数

fx397993401 2011-12-06 09:35:32
要求统计一个字符串中 各个子串出现的次数 。
比如 abcab 那么子串 ab 就出现了两次 ,子串abc 就出现了一次

...全文
1799 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
回复#23,我的说法有误,那个后缀树的深度应该是O(N)的,不过不影响后面的结论。因为trie树的叉是有限的,所以每走一层可以认为是O(1)的。

回复#24,你的后缀串排序不可能是O(n*logn),因为后缀串的长度并不全是O(1)的。它们之间的比较不能看做O(1)。不过对于你的算法还是没太看懂,例如求子串“a”的频率2,通过相邻的两个SubString是怎么得到的?
jie_huang 2011-12-23
  • 打赏
  • 举报
回复
复杂度有两方面,时间和空间。
这个问题,其实重要的是空间,因为如果构造所有的子串的换,极端情况,有n*(n+1)/2个。
最优算法之一:
Input:
const char input[n]

Algorithm:
Using SubString { int beginPos; int freq = 1} to present sub string of input from beginPos to n.
Sort all SubString by desc. Complexity = n log n
Scan result one by one
If prev contains current, current.freq += 1
End Scan
So, the total time complexity is n log n + n
if count the string comparison, (n log n + n) * n / 2
space complexity: n * 2, depends on sorting algorithm
用楼主的例子解释
Input: abcab
所以,有5个SubString,不是所有的子串。每个SubString用一个数字表示,这样不用占空间
0: abcab
1: bcab
2: cab
3: ab
4:b
排序后
3:cab
1:bcab
4:b
0:abcab
3:ab

扫描一次,得到频率

3:cab :1
1:bcab :1
4:b :2
0:abcab :1
3:ab :2
这里的关键是,如果需要,可以快速得到所有可能的子串(频率为1)。
通过两个相邻的SubString,去掉前面一个SubString的最后一个字符,直到和下一个SubString相同或者为空结束。
比如,所有可能的子串在bcab和b之间有
bca,bc
他们的频率都是1.

  • 打赏
  • 举报
回复
原来是所有子串,我还以为是人为给定的N个子串呢。

那确实应该用原字符串构造后缀树,这个后缀树应该是O(logN)深度的。
然后共有O(N*N)个子串,子串的平均长度是O(N),对每个子串与后缀树进行比对,那么复杂度也是O(N*N*N)的。
zmr0469 2011-12-20
  • 打赏
  • 举报
回复
典型的后缀树撒。。
i_love_ai 2011-12-20
  • 打赏
  • 举报
回复
kmp复杂度最好吗?
fx397993401 2011-12-20
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 nalt_ 的回复:]

为何要想得那么复杂
[/Quote]

你没看清楚 题目
TintinPig 2011-12-15
  • 打赏
  • 举报
回复
用数据结构的KMP串匹配模式算法去求
绿色夹克衫 2011-12-15
  • 打赏
  • 举报
回复
用hash的话实际上是O(n^3),因为计算长度比较长的字符的hash,是O(n)的,最好的应该是O(n^2)的,因为子串数量就是这个级别的,最坏情况下所有字符都不同,就会出现O(n^2)个子串。

[Quote=引用 15 楼 fx397993401 的回复:]

之前 我是想 用记录 字母的位置 ,然后用字典树 查找 ,但是 在这之前
是不是 需要 求出 全部的子串 出来呢 , 这个复杂度 就达到 n*n

一楼的复杂度 是 o(n*n)
那么 解决这个问题 的最好复杂度是多少 ,
[/Quote]
fx397993401 2011-12-15
  • 打赏
  • 举报
回复
之前 我是想 用记录 字母的位置 ,然后用字典树 查找 ,但是 在这之前
是不是 需要 求出 全部的子串 出来呢 , 这个复杂度 就达到 n*n

一楼的复杂度 是 o(n*n)
那么 解决这个问题 的最好复杂度是多少 ,
nuptxxp 2011-12-13
  • 打赏
  • 举报
回复
kmp算法可以的,
算法与kmp基本一致,就是找到模式串不要break,继续寻找下一个字串
假设原串长度为L1,模式串为L2,时间复杂度就为O(L1+L2)可以解决这个问题
cvanchen 2011-12-13
  • 打赏
  • 举报
回复
用kmp不行么
sincerejerry 2011-12-12
  • 打赏
  • 举报
回复
void main()
{
char str[100]={'\0'}; //输入原字符串
char subStr[10]={'\0'}; //输入子字符串
int num; //子字符串出现次数
printf("请输入原字符串:",str);
gets(str); //接收输入的字符串
printf("请输入子字符串:",subStr);
gets(subStr);
num = count(str, subStr);
printf("%d",num);
}
//判断subStr在str中出现的次数
int count(char* str, char* subStr)
{
int i, j, k, num = 0;
for(i=0; str[i]!='\0'; i++)
{
for (j=i, k = 0; str[j] == subStr[k] && str[j]!='\0'; k++,j++);
if (subStr[k]=='\0')
num++;
}
return num;
}
绿色夹克衫 2011-12-12
  • 打赏
  • 举报
回复
这个不就是后缀树么?把所有后缀都加到Trie里,最后遍历一下整个树,结果自然出来了。
  • 打赏
  • 举报
回复
将需要匹配的子串做成trie树。

然后对原串进行N次向后遍历,每次起始点向后移动一位。一边向后遍历一边增加trie树中节点对应的的数量。

例如在lz的例子:

子串的trie树

(a,0,mid)
/
(b,0,end)
/
(c,0,end)

分别遍历“abcab”,“bcab”,“cab”,“ab”,“b”,然后trie树变为

(a,2,mid)
/
(b,2,end)
/
(c,1,end)

其中标记为end的就是子串的结尾。
nuptxxp 2011-12-11
  • 打赏
  • 举报
回复
感觉kmp能解决这个问题
丈八涯 2011-12-10
  • 打赏
  • 举报
回复
依次取字串的长度进行查询并记录位置,这样速度应该是比较快的。
如:
abcab
子串 a:0,3
b:1,4
c:2
求子串ab的时候,子串a所记录的位置进行查询
同理 求abc的时候则有子串ab所记录的位置进行查询
龙腾冰 2011-12-10
  • 打赏
  • 举报
回复
学习了,怎么才能把算法学的很好呢
jiuhexuan 2011-12-07
  • 打赏
  • 举报
回复
推荐使用正则
循环各子字符串,匹配
wcj1018_net 2011-12-07
  • 打赏
  • 举报
回复
循环遍历一下,可以考虑用二分查找
xueyong4712816 2011-12-07
  • 打赏
  • 举报
回复
先把字符子串按顺序按照一定规律排序,然后在循环去匹配!
加载更多回复(3)
基于定长顺序存储结构实现对串的赋值、串比较、子串的位置、串替换等操作。要所有操作均以函数的形式实现,在主函数调用各个函数实现整体功能。 注意:每一个字符串的第一个元素存放的是该字符串的长度(不包括第一个元素),除串的赋值外,其他所有操作(比较、子串的位置、串替换)等都不应包含该字符。 1.1.实验1:串赋值函数实现: 按照系统已经定义的函数接口编写函数实体,实现:将输入数组StrInput[]的数据赋值给待赋值数组StrTobeAssigned[],其待赋值数组StrTobeAssigned[0]存放有效数据的长度,StrTobeAssigned[1]之后存放带赋值数据。 具体要和相关假设为: ① 函数接口定义为:int MyStrAssign(char * StrTobeAssigned, char * StrInput); ② 输入参数:待赋值字符串变量StrTobeAssigned,字符串的期望值StrInput; ③ 输出参数:无; ④ 处理规则及返回值:将StrTobeAssigned[1]及之后的内容赋值为StrInput的有效内容,StrTobeAssigned[0]赋值为StrInput有效字符的长度,并返回1; ⑤ 假设: a)两个字符串均不为空串; b)StrInput存放的是一个完成的字符串(不包含长度); c)赞不考虑输入数据超过数组总长度的情况。 1.2实验2:串替换函数: 按照系统已经定义的函数接口编写函数实体,实现:在主串MainStr查找是否存在某特定子串SubStr1,若存在则将所有的SubStr1替换为新的指定子串SubStr2,函数返回字符串替换的次数。 具体要和相关假设为: ① 函数接口定义为:int MyStrReplace(char * MainStr, char * SubStr1, char * SubStr2); ② 输入参数:主串变量MainStr,子串变量SubStr1,SubStr2; ③ 输出参数:无; ④ 处理规则及返回值:若主串存在子串,用SubStr2替换主串MainStr出现的所有与SubStr1相同的不重叠的子串,并返回字符串替换的次数;否则返回0。 ⑤ 假设: a)主串和两个子串均不为空串; b)MainStr[0]和SubStr1[0],SubStr2[0]分别存放对应字符串的长度,不用替换该部分。 2.问题分析 (1)根据实验一的内容可知,我们需要通过编写函数实体的形式实现串的赋值操作,主要的思路包括: (a)获得输入字符串的长度len; (b)将输入字符串的长度len赋值给待赋值字符串的第一个元素StrTobeAssigned[0]; (c)依次将输入字符串的数据赋值给待赋值字符串。 (2)根据实验二的内容可知,我们需要通过编写函数实体的形式实现串的替换操作,主要的思路包括: (a)遍历主串MainStr,检查是否存在某特定子串SubStr1; (b)如果存在则找到子串在主串的位置; (c)在主串删除该子串并更新主串长度; (d)在主串插入该子串并更新主串长度; (e)过程记录替换字符串次数,遍历结束后返回该次数(如果没有替换则为0); 如果有必要,可以使用本实验已经提供的相关函数,如:子串位置的函数MySubStrIndex(),子串删除函数MyStrDelete()和子串插入函数MyStrInsert()等
课程介绍:第一章:正则表达式(regularexpression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串取出符合某个条件的子串等。第二章:http协议是一种无状态协议,不记录用户行为,我们可以利用cookie记录数据,方便用户操作,提升用户体验。第三章:ECMAScript6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。第四章:本章主要讲解JS动画原理、动画函数封装和轮播。第五章:本章主要讲解面向对象、构造函数和继承、原型链和继承。第六章:本节课程主要讲解了什么是Ajax、如何使用Ajax发送get请、如何使用Ajax发送post请、JSON数据格式、回调地狱、Promise和Ajax的同源策略、跨域请。第七章:本章主要讲解html、val、attr、prop、class、全选框、动画、节点遍历、ajax、sonp、event、multiple、plugin、plugin、magnifier。第八章:本章主要讲解UML类图、单例模式、工厂模式、策略模式、代理模式、观察者模式。第九章:本章主要讲解为什么要模块化、原生JS,模块的写法、AMD、CommonJS&Webpack。第十章:本节课程主要讲解了服务器安装环境配置、端口及ip基本常识、简单认识PHP(helloworld)、基本语法和动态网页原理。第十一章:本节课程主要讲解了什么是SASS、SASS的预处理、ass语法(变量、嵌套、导入、mixin、扩展、function、expression)。第十二章:本节课程主要讲解了什么是GULP、GULP环境配置、GULP基本使用及GULP的插件安装与使用。

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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