遇到的一个关于查找的算法,国外有人控制在30秒内,我却要6分钟,求助算法帝
时间:2011-10-12
来源:互联网
问题大概是这样的,有一个设备,通过串口与主机相连。这个设备内部有一个很大的存储区域,假设可以超过10GB,这个存储区域存储的是一个很大的字符串,格式大概是这样子:
00011111111111122222222222
333333333333
4444444444400000001111111
22222223333344444
也就是由N个连续的0,1,2,3,4组成,这个N是变化的,而不是常量。现在我有一个函数,可以读取这个设备上指定位置的字符串的值。设函数原型为Function GetPosValue(Byval pos As Long) as String
pos是字符串的位置,从1到字符串的长度。
比如 GetPosValue(1)返回0,GetPosValue(4)返回1。这个函数每调用一次都会访问串口设备,大家知道串口是很慢的,所以这个函数会消耗大量时间。
现在,我想把这个设备的所有字符串都读出来保存到一个文件。假设我还有一个函数GetMaxPos()可以用来得到设备上字符串的长度,那么,最简单,也是最慢的算法如下:
open "filename" for append as #1
MaxPos=GetMaxPos()
For i=1 to MaxPos
m=GetPosValue(4)
Print #1,m;
Next
这个办法很好,但却是最糟糕,最慢的办法。
现在已知这个设备字符串还有一些这样的特性:它总是由若干个连续的0,1,2,3,4组成,每次0结束了就跳转到1,1结束了跳转到2,2结束跳转到3,3结束跳转到4,4结束又跳转到0,以此循环。但是每次每种字符连续出现的次数又不是确定的。比如其中的一段为0001111222233333,这段中0连续出现3次,1连续出现4次,2连续出现4次,3连续出现5次。现在又知,每种字符连续出现的次数虽然不确定,但是有一个最大值MaxTime和一个最小值MinTime。比如如果这个设备的MinTime=3,MaxTime=5,则表示某个数值必须出现最少3次,最大5次,也就是000111这样的序列可能出现在设备中,而00111111222333这样的序列不可能出现在设备中,因为这里0只连续出现了2次,小于了MinTime,而1出现了6次,大于MaxTime。
在这种已知条件下,寻求一种算法,能够读出设备中的全部字符串,且调用GetPosValue()函数的次数最少(因为这个函数调用很慢)
在实际情况中,MinTime和MaxTime都是很大的值,比如MinTime可能会超过1000,那么某个数值的连续长度会很大。
我们已经尝试过的算法:
假设MinTime=1000
那么 当GetPosValue(1)="0"的时候,GetPosValue(1000)肯定也等于"0",那么1--1000的长度就全是0,只需要调用两次GetPosValue函数就可以确定这段范围(不需要再调用1000次GetPosValue函数了)。根据这样的思想,我们总是以MinTime跳跃遍历的位置,每次跳跃,调用一次GetPosValue函数检查当前的字符是否等于前一个字符,如果相等,表示还在前一个字符的范围,那么继续跳跃一个MinTime长度。如果不相等,说明已经来到下一个字符的范围,那么我们需要确定这个字符与前一个字符的分界线位置,那么程序会回溯到跳跃前的位置,使用二分法查找分界线。 比如 00000000000111111111111111中,位置第11个字符就是0与1的分界线。我们需要找到这个分界处。那么就可以确定每段的长度,并且减少GetPosValue函数的调用次数。但是以MinTime来跳跃还是比较慢的,为了提高速度,我们使用 MinTime + (MaxTime-MinTime)/2 来跳跃,但是这样的话,可以出现跳过的情况,比如000111222333444000,从开始的0跳过15个字符后,又是0,结果程序会以为还在第一段0的范围,其实已经到了第二段0的范围了。
“跳过”的情况是比较麻烦的,如果要保证完全不跳过,那么精确的算法就会很慢。所以现在我们允许出现跳过,这样会使得到的结果与原始设备的字符串有所误差。现在我们允许这种误差,但是要速度尽可能快(也就是调用GetMaxPos函数的次数最少),误差尽可能小。不知道大家有没有好点的办法?请大家帮帮忙,谢谢啦
00011111111111122222222222
333333333333
4444444444400000001111111
22222223333344444
也就是由N个连续的0,1,2,3,4组成,这个N是变化的,而不是常量。现在我有一个函数,可以读取这个设备上指定位置的字符串的值。设函数原型为Function GetPosValue(Byval pos As Long) as String
pos是字符串的位置,从1到字符串的长度。
比如 GetPosValue(1)返回0,GetPosValue(4)返回1。这个函数每调用一次都会访问串口设备,大家知道串口是很慢的,所以这个函数会消耗大量时间。
现在,我想把这个设备的所有字符串都读出来保存到一个文件。假设我还有一个函数GetMaxPos()可以用来得到设备上字符串的长度,那么,最简单,也是最慢的算法如下:
open "filename" for append as #1
MaxPos=GetMaxPos()
For i=1 to MaxPos
m=GetPosValue(4)
Print #1,m;
Next
这个办法很好,但却是最糟糕,最慢的办法。
现在已知这个设备字符串还有一些这样的特性:它总是由若干个连续的0,1,2,3,4组成,每次0结束了就跳转到1,1结束了跳转到2,2结束跳转到3,3结束跳转到4,4结束又跳转到0,以此循环。但是每次每种字符连续出现的次数又不是确定的。比如其中的一段为0001111222233333,这段中0连续出现3次,1连续出现4次,2连续出现4次,3连续出现5次。现在又知,每种字符连续出现的次数虽然不确定,但是有一个最大值MaxTime和一个最小值MinTime。比如如果这个设备的MinTime=3,MaxTime=5,则表示某个数值必须出现最少3次,最大5次,也就是000111这样的序列可能出现在设备中,而00111111222333这样的序列不可能出现在设备中,因为这里0只连续出现了2次,小于了MinTime,而1出现了6次,大于MaxTime。
在这种已知条件下,寻求一种算法,能够读出设备中的全部字符串,且调用GetPosValue()函数的次数最少(因为这个函数调用很慢)
在实际情况中,MinTime和MaxTime都是很大的值,比如MinTime可能会超过1000,那么某个数值的连续长度会很大。
我们已经尝试过的算法:
假设MinTime=1000
那么 当GetPosValue(1)="0"的时候,GetPosValue(1000)肯定也等于"0",那么1--1000的长度就全是0,只需要调用两次GetPosValue函数就可以确定这段范围(不需要再调用1000次GetPosValue函数了)。根据这样的思想,我们总是以MinTime跳跃遍历的位置,每次跳跃,调用一次GetPosValue函数检查当前的字符是否等于前一个字符,如果相等,表示还在前一个字符的范围,那么继续跳跃一个MinTime长度。如果不相等,说明已经来到下一个字符的范围,那么我们需要确定这个字符与前一个字符的分界线位置,那么程序会回溯到跳跃前的位置,使用二分法查找分界线。 比如 00000000000111111111111111中,位置第11个字符就是0与1的分界线。我们需要找到这个分界处。那么就可以确定每段的长度,并且减少GetPosValue函数的调用次数。但是以MinTime来跳跃还是比较慢的,为了提高速度,我们使用 MinTime + (MaxTime-MinTime)/2 来跳跃,但是这样的话,可以出现跳过的情况,比如000111222333444000,从开始的0跳过15个字符后,又是0,结果程序会以为还在第一段0的范围,其实已经到了第二段0的范围了。
“跳过”的情况是比较麻烦的,如果要保证完全不跳过,那么精确的算法就会很慢。所以现在我们允许出现跳过,这样会使得到的结果与原始设备的字符串有所误差。现在我们允许这种误差,但是要速度尽可能快(也就是调用GetMaxPos函数的次数最少),误差尽可能小。不知道大家有没有好点的办法?请大家帮帮忙,谢谢啦
作者: hd378 发布时间: 2011-10-12
什么设备运行操作内存吗?
10G光是赋值和判断,以VB6的速度就占了很多时间了。
10G光是赋值和判断,以VB6的速度就占了很多时间了。
作者: AisaC 发布时间: 2011-10-12
什么设备,允许运行操作内存吗?
作者: AisaC 发布时间: 2011-10-12
不允许,只能使用GetPosValue函数一次读一个指定位置的字符。现在不考虑语言环境等因素,只考虑算法,有什么好办法吗?
作者: hd378 发布时间: 2011-10-12
是什么acm题吗?把原题贴出来吧
作者: libralibra 发布时间: 2011-10-12
没看懂具体想实现什么?具备什么条件?
有时候就是因为这种问题影响到架构,而提问的人还觉得架构是可行的,可能给出个不可能实现的虚拟问题。这种不明朗的问题,还是自己吞了吧。
有时候就是因为这种问题影响到架构,而提问的人还觉得架构是可行的,可能给出个不可能实现的虚拟问题。这种不明朗的问题,还是自己吞了吧。
作者: SupermanKing 发布时间: 2011-10-12
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28