解决方案 »
- 是否无法手动取消并行的 Task?
- C#用HttpWebRequest 链接Web 链接超时。是怎么回事?
- 为什么visual studio 2008经常莫名其妙地报错?求教高手
- 关于判断 string时string 为null
- 查询orcl数据库并导出成word或excel有格式要求
- 怎样才能使RichTextBox的最后一行被选中?
- winform
- 微软Visual C# 组的项目经理出的小测验,大家都来试试。。。
- 大侠们 ,关于error CS0122 SchemaMapping ~~~~!!!!
- VC代码在C#中的改造问题
- 读取数据很慢如何解决
- 给多个PictureBox添加一个右键Delete,多个PictureBox对应的Click事件处理函数是同一个,怎么清除指定的PicBox的图片
什么样的子串算一个句子
程序的目标只需要找到一对相同的就可以了吗
几十万单词 平均一个单词算10个字节也只占几M的内存 按句子的字符串全部进行HASH不就完了吗
{
FileStream fs = File.Open(@"C:\The Three Musketeers(三剑客).txt", FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
int ch, lastch = 0;
string[] aryText;
string orgText;
List<Sentence> wordarray = new List<Sentence>();
Dictionary<string, List<Sentence>> dict = new Dictionary<string, List<Sentence>>();
Dictionary<string, List<Sentence>> newdict;
StringBuilder sb = new StringBuilder();
StringBuilder orgsb = new StringBuilder();
int words = 0, chars = 0, startchars = 0;
while ((ch = sr.Read()) != -1)
{
chars++;
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
{
sb.Append(((char)ch).ToString().ToLower());
}
else
{
if ((lastch >= 'a' && lastch <= 'z') || (lastch >= 'A' && lastch <= 'Z'))
{
sb.Append(" ");
Sentence sentence;
sentence.start = words;
sentence.pos = startchars;
wordarray.Add(sentence);
words++;
}
startchars = chars;
}
orgsb.Append((char)ch);
lastch = ch;
} fs.Close();
orgText = orgsb.ToString();
aryText = sb.ToString().Split(' ');
for (int i = 0; i < aryText.Length - 1; i++)
{
string key = aryText[i] + " " + aryText[i + 1];
if (dict.ContainsKey(key))
dict[key].Add(wordarray[i]);
else
(dict[key] = new List<Sentence>()).Add(wordarray[i]);
}
int sentencelen = 1;
while (true)
{
newdict = new Dictionary<string, List<Sentence>>();
sentencelen++;
foreach (var sentence in dict.Keys)
{
if (dict[sentence].Count > 1)
{
foreach (Sentence s in dict[sentence])
{
if (s.start + sentencelen < aryText.Length)
{
string key = sentence + " " + aryText[s.start + sentencelen];
if (newdict.ContainsKey(key))
newdict[key].Add(s);
else
(newdict[key] = new List<Sentence>()).Add(s);
}
}
}
}
if (newdict.Count == 0)
break;
dict = newdict;
}
Console.WriteLine("最长重复句子是: \"{0}\".", dict.Keys.ToList()[0]);
dict.Values.ToList().ForEach(x => { Console.WriteLine("原文位于({1}):{0}...", orgText.Substring(x[0].pos, 100), x[0].pos); }); }
struct Sentence
{
public int start;
public int pos;
}
输出:最长重复句子是: "read dec it is by more order and for the good of the state that the bearer of this has done what he has done richelieu and".
原文位于(912706):read:Dec. 3, 1627
It is by more order and for the good of the state that the
bearer of this ha...
原文位于(939717):read:Dec. 3, 1627
It is by more order and for the good of the state that the
bearer of this ha...
以单词为单位,把文章所有的后缀放入一个数组(存放指针就好),
对这个数组排序,每每相邻的记录最长前缀空间复杂度O(n), 时间复杂度n*m*log(n) (字符串比较是一个个字母比的!不是nlogn!)
10万个句子大概200兆内存,如果只存词的引用指针的话。
参考http://www.cnblogs.com/dullwolf/archive/2011/04/15/2017479.html速度肯定是快的,而且可以做Like查找。
想了几天,终于有点思路!下面说说我的想法。
假设已知道一个符串的最长重复子串长度为N,再读入一个字符后,该字符串的最长重复子串长度只有两种情况N或N+1;而且只N+1的情况只可能是倒数N+1个字符构成的子串。
如:abcab 最大重复子串长度为2,再读入一字符c,字符串变为abcabc,最大重复子串长度为3,子串为abc;
该结论的证明我还没完善好,改天给大家贴出来;
下面是算法的C语言实现:为了简化编程,我们暂且假设字符串已读到内存中:#include <stdio.h>int main(void)
{
char array[]="abcabc"; int length=0;/*记录当前已求得的最长重复子串长度*/
char *temp;/*用于指向读入字符后可能构成最长重复子串长度为length+1的子串的首字母*/ char *p,*q;/*p指向刚读入的字符*/ int flag=1;/*如果读入字符后可能构成最长重复子串长度为length+1的子串,flag=1*/ int i;
p=array;
while(*p!='\0')
{
temp=p-length; for(q=array;q<temp;q++)/*从头开始比较长度为length+1的所有子串*/
{
flag=1;
for(i=0;i<=length;i++)
{
if(*(q+i)!=*(temp+i))
{
flag=0;
break;
}
}
if(flag)
{
length++;
q=array;/*重新比较,也可以直接退出循环,主要是为了保险*/
}
}
p++;
}
printf("%d\n",length);/*只打印出最长重复子串的长度*/
return 0;
}补充:1。中间的字符串比较用一个函数会更好;
2。可以记录下最长重复子串的位置,输出子串
看到楼上说用后缀数组,可能更好,正在学习中