ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
Python自动化办公应用大全 Excel 2021函数公式学习大典 Kutools for Office 套件发布 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: guangyp

[分享]我参与18期竞赛题后写的一个编程经验总结

[复制链接]

TA的精华主题

TA的得分主题

发表于 2006-12-25 21:44 | 显示全部楼层
这个看不明白,但楼主真的用心做了佩服

TA的精华主题

TA的得分主题

发表于 2011-10-14 14:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2011-10-14 15:40 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 香川群子 于 2011-10-14 16:12 编辑

有趣。

说一下我的思路:
1. 逐个检查数值,如果是>2的数值,并且它的前面是【空值,或0,或>2】,则可以马上置换成字母。
2. 余下数值用递归法组合后置换。

下面是第一步的预处理代码。

如果没有1、2数字出现的话,到这里就已经结束置换,直接输出结果了。

  1. Sub codecombin()
  2. Randomize
  3. [a1] = Int(10 ^ (Rnd() * 10))
  4. s = "0" & [a1]
  5. l = Len(s)
  6. t = Left(s, 1)
  7. For i = 2 To l
  8. t0 = t
  9. t = Mid(s, i, 1)
  10. If t > "2" Then
  11. If t0 > "2" Or t0 = "0" Then
  12. s = Left(s, i - 1) & Chr(64 + Val(t)) & Right(s, l - i)
  13. End If
  14. ElseIf t = 0 Then
  15. If t0 = "1" Or t0 = "2" Then
  16. Else
  17. s = Left(s, i - 1) & " " & Right(s, l - i)
  18. End If
  19. End If
  20. Next
  21. s = Replace(Mid(s, 2), " ", "")
  22. [a2] = s
  23. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2011-10-14 21:38 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 香川群子 于 2011-10-15 00:44 编辑
winland 发表于 2006-12-25 12:41
我把我的递归方法改了一下, 用上了数组, 速度也快了很多, 23个1大概两到三秒.

我自己写的递归迭代方法,23个1 ,光计算是0.6秒,连写入单元格是2.8秒。而楼主最快的第6稿代码在我的机子上是8.14秒。
因此,显然比楼主的代码快多了。

  1. Public brr(), k As Long
  2. Sub codecombin()
  3.     [c2] = Timer
  4.     Randomize
  5.     [a:b].Clear
  6.    
  7.     s = Int(10 ^ (Rnd() * 10))
  8.     Do
  9.         l = InStr(s, 0)
  10.         If l = 0 Then Exit Do
  11.         t = Mid(s, l - 1, 1)
  12.         If t > "2" Or t = " " Then
  13.             s = Left(s, l - 1) & Mid(s, l + 1)
  14.         Else
  15.             s = Left(s, l - 1) & "o" & Mid(s, l + 1)
  16.         End If
  17.     Loop
  18.     s = Replace(s, "o", 0)
  19.     '以上为得到随机数值,并检查、去掉不合理和多余的0
  20.    
  21. '    s = String(23, "1") '最大23个重复1的检测
  22. '    s = "6" '调试bug
  23.    
  24.     [a1] = "' " & s
  25.     [c1] = Timer
  26.    
  27.     If Len(s) = 1 Then
  28.         s = Chr(64 + Val(s))
  29.         [a2] = s
  30.         [b2] = CodeChk(s)
  31.         [c1] = Timer - [c1]
  32.         [c2] = Timer - [c2]
  33.         Exit Sub
  34.     End If
  35.     '以上为一位数值时直接转换为字母并结束。
  36.    
  37.     s = " " & s & "  "
  38.     l = Len(s)
  39.    
  40.     t = Left(s, 1)
  41.     For i = 2 To l - 2
  42.         t0 = t
  43.         t = Mid(s, i, 1)
  44.         If t = "0" Then
  45.             s = Left(s, i - 2) & " " & Chr(64 + Val(Mid(s, i - 1, 2))) & Right(s, l - i)
  46.         ElseIf t = "1" Then
  47.             If t0 = " " Or t0 = "0" Or t0 > "2" Then
  48.                 If Mid(s, i + 2, 1) = "0" Or Mid(s, i + 1, 2) = "  " Then
  49.                     s = Left(s, i - 1) & "A" & Right(s, l - i)
  50. '                    s = Left(s, i - 1) & Chr(64 + Val(t)) & Right(s, l - i)
  51.                 End If
  52.             End If
  53.         ElseIf t = "2" Then
  54.             If t0 = " " Or t0 = "0" Or t0 > "2" Then
  55.                 If Mid(s, i + 1, 1) > "6" Or Mid(s, i + 2, 1) = "0" Or Mid(s, i + 1, 2) = "  " Then
  56.                     s = Left(s, i - 1) & "B" & Right(s, l - i)
  57. '                    s = Left(s, i - 1) & Chr(64 + Val(t)) & Right(s, l - i)
  58.                 End If
  59.             End If
  60.         ElseIf t > "2" Then
  61.             If t0 = " " Or t0 = "0" Or t0 > "2" Or (t0 = "2" And t > "6") Then
  62.                 s = Left(s, i - 1) & Chr(64 + Val(t)) & Right(s, l - i)
  63.             End If
  64.         End If
  65.     Next
  66.     '以上为检查各数值,如无分歧则直接转换为字母。
  67.    
  68.     s = Replace(Mid(s, 2), " ", "")
  69.     [a2] = s
  70.    
  71.     n1 = InStr(s, 1):     n2 = InStr(s, 2)
  72.     If n1 * n2 Then
  73.         If n1 < n2 Then t = n1 Else t = n2
  74.     Else
  75.         t = n1 + n2
  76.     End If
  77.     '以上为检查转换结果中是否还含有数字1或2。
  78.    
  79.     If t = 0 Then
  80.         [b2] = CodeChk(s)
  81.         [c1] = Timer - [c1]
  82.         [c2] = Timer - [c2]
  83.         Exit Sub
  84.     End If
  85.     '以上为,检查结果中已经不含1或2时,肯定没有分歧了,可以直接输出转换字母结果。
  86.    
  87.     k = 0
  88.     ReDim brr(1 To 65536, 1 To 2)
  89.    
  90.     dg s, t
  91.     '开始递归过程……
  92.     [c1] = Timer - [c1]
  93.     '递归结束,已经得到储存在数组brr中的最终结果。
  94.    
  95.     s = "'" & [a1]
  96.     For i = 1 To k
  97.         brr(i, 2) = CodeChk(brr(i, 1))
  98.         If brr(i, 2) <> s Then
  99.             MsgBox "Err"
  100.         End If
  101.     Next
  102.     '以上为对转换字母结果逐一确认,再转换为数值时是否相同。
  103.    
  104.     [a2].Resize(k, 2) = brr 'WorksheetFunction.Transpose(brr)
  105.     [c2] = Timer - [c2]
  106.     '以上为把数组brr中的最终结果输出到工作表,结束。
  107.    
  108. End Sub
  109. Sub dg(A, n)
  110.     b = Mid(A, n, 1)
  111.     If IsNumeric(b) Then
  112.         If b > "2" Then
  113.             A = Left(A, n - 1) & Chr(64 + Val(b)) & Right(A, Len(A) - n)
  114. '        ElseIf b = "0" Then
  115. '            A = Left(A, n - 1) & Right(A, Len(A) - n)
  116.         Else
  117.             a1 = Left(A, n - 1) & Chr(64 + Val(b)) & Right(A, Len(A) - n)
  118.             If n < Len(a1) Then
  119.                 dg a1, n + 1
  120.             Else
  121.                 k = k + 1
  122.                 brr(k, 1) = a1
  123.                 Exit Sub
  124.             End If
  125.             
  126.             If IsNumeric(Mid(A, n + 1, 1)) Then
  127.                 a2 = Left(A, n - 1) & Chr(64 + Val(Mid(A, n, 2))) & Right(A, Len(A) - n - 1)
  128.                 For i = n + 1 To Len(a2)
  129.                     If IsNumeric(Mid(a2, i, 1)) Then
  130.                         dg a2, i
  131.                         Exit Sub
  132.                     End If
  133.                 Next
  134.                 k = k + 1
  135.                 brr(k, 1) = a2
  136.             End If
  137.             
  138.             Exit Sub
  139.         End If
  140.     End If
  141.     n1 = InStr(A, 1):    n2 = InStr(A, 2)
  142.     If n1 * n2 Then
  143.         If n1 < n2 Then t = n1 Else t = n2
  144.     Else
  145.         t = n1 + n2
  146.         If t = 0 Then
  147.             k = k + 1
  148.             brr(k, 1) = A
  149.             Exit Sub
  150.         End If
  151.     End If
  152.     dg A, t
  153.    
  154. End Sub
  155. Function CodeChk(A)
  156.     t = "' "
  157.     For i = 1 To Len(A)
  158.         t = t & Asc(Mid(A, i, 1)) - 64
  159.     Next
  160.     CodeChk = t
  161. End Function
复制代码

TA的精华主题

TA的得分主题

发表于 2011-10-14 21:44 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 香川群子 于 2011-10-15 00:43 编辑

这个,实际上是我第一次独立写递归迭代的过程代码。

很有纪念意义地说。

下面是递归过程代码。

  1. Sub dg(A, n)
  2.     b = Mid(A, n, 1)
  3.     If IsNumeric(b) Then
  4.         If b > "2" Then
  5.             A = Left(A, n - 1) & Chr(64 + Val(b)) & Right(A, Len(A) - n)
  6. '        ElseIf b = "0" Then
  7. '            A = Left(A, n - 1) & Right(A, Len(A) - n)
  8.         Else
  9.             a1 = Left(A, n - 1) & Chr(64 + Val(b)) & Right(A, Len(A) - n)
  10.             If n < Len(a1) Then
  11.                 dg a1, n + 1
  12.             Else
  13.                 k = k + 1
  14.                 brr(k, 1) = a1
  15.                 Exit Sub
  16.             End If
  17.             
  18.             If IsNumeric(Mid(A, n + 1, 1)) Then
  19.                 a2 = Left(A, n - 1) & Chr(64 + Val(Mid(A, n, 2))) & Right(A, Len(A) - n - 1)
  20.                 For i = n + 1 To Len(a2)
  21.                     If IsNumeric(Mid(a2, i, 1)) Then
  22.                         dg a2, i
  23.                         Exit Sub
  24.                     End If
  25.                 Next
  26.                 k = k + 1
  27.                 brr(k, 1) = a2
  28.             End If
  29.             
  30.             Exit Sub
  31.         End If
  32.     End If
  33.     n1 = InStr(A, 1):    n2 = InStr(A, 2)
  34.     If n1 * n2 Then
  35.         If n1 < n2 Then t = n1 Else t = n2
  36.     Else
  37.         t = n1 + n2
  38.         If t = 0 Then
  39.             k = k + 1
  40.             brr(k, 1) = A
  41.             Exit Sub
  42.         End If
  43.     End If
  44.     dg A, t
  45.    
  46. End Sub
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2011-10-15 00:41 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
前面代码中,加入一段,去掉了随机产生数中不合理的、多余的0
  1. s = Int(10 ^ (Rnd() * 10))
  2.     Do
  3.         l = InStr(s, 0)
  4.         If l = 0 Then Exit Do
  5.         t = Mid(s, l - 1, 1)
  6.         If t > "2" Or t = " " Then
  7.             s = Left(s, l - 1) & Mid(s, l + 1)
  8.         Else
  9.             s = Left(s, l - 1) & "o" & Mid(s, l + 1)
  10.         End If
  11.     Loop
  12.     s = Replace(s, "o", 0)
复制代码
最后,增加了一个检查所得字母按密码转换的结果,可以判断所得字母是否正确。、
  1. Function CodeChk(A)
  2.     t = "' "
  3.     For i = 1 To Len(A)
  4.         t = t & Asc(Mid(A, i, 1)) - 64
  5.     Next
  6.     CodeChk = t
  7. End Function
复制代码
请看附件。

或许还可以再优化一点。

code.rar

14.24 KB, 下载次数: 8

TA的精华主题

TA的得分主题

发表于 2011-10-15 20:25 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 香川群子 于 2011-10-15 20:42 编辑

前面的递归,是对数字的计算,查找、判断后把数值置换为相应字母。


下面重新写了一个代码,做法是先把数值全部转化为标准字母,
然后,对于含"A"和"B"字母的部分,再作二次迭代置换。

虽然速度上改进不大,但是代码相当简洁好读了。

  1. Public brr() As String, d, k As Long
  2. Sub CodeRp()
  3.     tms = Timer
  4.     [g2].CurrentRegion.Clear '清空将要输出数据的区域
  5.    
  6.     s = [e1] '获取要置换的数值
  7.     s = Replace(s, 10, "J") '先把10置换为J
  8.     s = Replace(s, 20, "T") '再把20置换为T
  9.     s = Replace(s, 0, "") '如果还有多余的0,去除。
  10.     For i = 1 To 9
  11.         s = Replace(s, i, Chr(i + 64)) '把1-9,分别置换为A,B,C,D,E,F,G,H,I的字母。
  12.     Next
  13.    
  14.     [g1] = s '这样,已经得到了最标准的一个置换答案的文字列了。
  15.     If InStr(s, "A") + InStr(s, "B") Then '检查如果该文字列还含有A或B字符,则需要二次置换。
  16.         Set d = CreateObject("Scripting.Dictionary") '首先设置二次置换用的置换规则词典
  17.         For i = 1 To 9 '字典中加入AA,AB,AC,AD,AE,AF,AG,AH,AI 共9个单词,对应置换结果为K,L,M,N,O,P,Q,R,S
  18.             d("A" & Chr(i + 64)) = Chr(10 + i + 64)
  19.         Next
  20.         For i = 1 To 6 '字典中加入BA,BB,BC,BD,BE,BF 共6个单词,对应置换结果为U,V,W,X,Y,Z
  21.             d("B" & Chr(i + 64)) = Chr(20 + i + 64)
  22.         Next
  23.         
  24.         ReDim brr(1 To 65536) As String '定义结果数组brr
  25.         k = 1: brr(k) = s '加入第一标准置换结果。(含未置换的A,B字符)
  26.         
  27.         rp s, 1 '调用迭代递归过程代码rp,第一参数为需要检查置换的对象文字列s,第二参数为检查起始位置n=1。
  28.         
  29.     End If
  30.    
  31.     [g2].Resize(k) = WorksheetFunction.Transpose(brr) '输出数组brr结果到工作表。
  32. End Sub
复制代码
上面是过程主代码,下面是递归(迭代)过程代码,做法相当简单。

  1. Sub rp(t, n) '对文字列t,从第n个字符开始检查置换,直至最后
  2.     For i = n To Len(t) - 1 '检查开始字符n 会随着迭代计算过程的进行而改变
  3.         If Mid(t, i, 1) = "A" Or Mid(t, i, 1) = "B" Then '从n开始逐个检查字符,如果有A或B则需要检查
  4.             If d.Exists(Mid(t, i, 2)) Then '检查如果该字符即后面的2个字符符合置换条件(即在词典中存在)
  5.                 t1 = Left(t, i - 1) & d(Mid(t, i, 2)) & Mid(t, i + 2) '则按字典规则置换
  6.                 k = k + 1: brr(k) = t1 '置换结果写入结果数组brr
  7.                 If InStr(t1, "A") + InStr(t1, "B") Then '接着检查确认新的文字列t1中,是否还含有A或B需要置换
  8.                     rp t1, i + 1 '如果含有A或B,则使用迭代过程继续进行递归计算。
  9.                 End If
  10.             End If
  11.         End If
  12.     Next '检查所有字符直至结束
  13. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2011-10-15 22:43 | 显示全部楼层
本帖最后由 香川群子 于 2011-10-15 22:48 编辑

4种代码比较:

6楼winland 递归置换代码 速度最快。
唯一缺点是对0的处理尚存bug。

我14楼贴出的数值递归置换代码与之相对应,
速度稍慢,但解决了0的问题。

上面二个代码,得到的最后结果,很自然就已经是按照A-Z排序的结果了。
呵呵。这个大概是因为置换顺序本来就是升序的。

而我17楼的按字母方式递归置换代码,
速度稍快些,但仍不及6楼winland的效率高。

但是有一个显而易见的优点,代码简洁易懂。尤其是递归部分,简单到不能再简单了吧。

但是,带来的一个后果,所有组合结果的顺序,并不是A-Z从小到大升序排列,而是比较乱。
原因当然是置换规则造成的啦。


最后,是楼主2006年的代码。

虽然一再改进,但因为是在一个过程内反复检查循环,所以速度和递归无法比,大约要慢20倍。
估计无法进一步改善了。(因为重复检查实际上相当多。)


最后是结果排序方面,也是比较乱的。


TA的精华主题

TA的得分主题

发表于 2011-10-15 23:16 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
现在又发现新情况。

在做随机测试时,发现楼主的代码有严重缺陷……漏数据。

测试: 1398213134 时,应该有12个结果:
ACIHBACACD
ACIHBACMD
ACIHBMACD
ACIHBMMD
ACIHUCACD
ACIHUCMD
MIHBACACD
MIHBACMD
MIHBMACD
MIHBMMD
MIHUCACD
MIHUCMD

但楼主代码只有7个:
ACIHBACACD
MIHBACACD
ACIHUCACD
MIHBMACD
MIHUCACD
MIHBMMD
MIHUCMD

少了最后置换的5个:
ACIHBACMD
ACIHBMACD
ACIHBMMD
ACIHUCMD
MIHBACMD


…………
然后,用123123123
以及121212等数据做检查,再次发现同样的缺漏。


并且,我检查了楼主所有6个稿,
最后结论,很不幸地,楼主的6个稿,结果都存在这样的严重缺陷。

只能不及格了。

呵呵。


请看附件,4种代码都放进去了,可以比较一下。



code 4.rar

30.78 KB, 下载次数: 20

TA的精华主题

TA的得分主题

发表于 2011-10-19 10:36 | 显示全部楼层
初步确认,楼主的代码,能够处理111111……

但不能处理222222……的转化。


详细原因待确认。

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2025-12-14 22:15 , Processed in 0.026976 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表