楼主: rollingpig

[精华] 分享一下SQL数据库编程大赛第二期我的解法

[复制链接]
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
11#
 楼主| 发表于 2011-3-29 14:59 | 只看该作者
最遗憾的就是在处理对角线时,没有用 *10 的方式来处理,导致整个code的可读性下降和性能的稍微下降,如果但是采用*10的方式,自己就很满意了.

对于我来说,最满意的写法应该是:


  1. with
  2. linesrc(line,linenum) as (   -- 生成 01010串
  3.       select replace(linestr,',') line ,to_number(replace(linestr,','))
  4.     from (
  5.       select sys_connect_by_path(bit,',') linestr,level LevelN
  6.       from (
  7.         select 0 bit from dual
  8.         union all
  9.         select 1 from dual
  10.       )
  11.       connect by level <= :n
  12.     )where LevelN=:n
  13.   and length(linestr)-length(replace(linestr,1))=:m     -- 每行正好m个球.
  14. ),
  15. solution(LevelN ,solutionStrings, cmp1,cmp2,cmp3 ) as (
  16.   select
  17.      1 --LevelN
  18.     ,line -- solutionStrings
  19.     ,linenum
  20.     ,linenum
  21.     ,linenum * power(10,:n-1)
  22.   from linesrc  
  23.   where line>=reverse(line)  --预先过滤左右对称
  24.   union all
  25.   select
  26.     LevelN +1  
  27.     ,solutionStrings || line
  28.     ,cmp1+linenum     
  29.     ,cmp2+linenum*power(10,levelN)     
  30.     ,cmp3+linenum*power(10,:n-levelN-1)     
  31.   from solution,linesrc     
  32.   where
  33.   levelN<:n and
  34.   instr((cmp1+linenum ) || ( cmp2+linenum*power(10,levelN))  || (cmp3+linenum*power(10,:n-levelN-1)) ,:m+1 ) =0
  35. ),
  36. solution2(solutionStrings) as(  -- original solution
  37.   select /*+ materialize */  solutionStrings from   solution
  38.   where LevelN=:n
  39. )
  40. ,
  41. symmtmp(blockN,xo,yo,xx,yy) as (  --base table for  对称判断.
  42.   select /*+ materialize */  rownum-1 ,mod(rownum-1,:n),floor((rownum-1)/:n)  , :n-1-mod(rownum-1,:n),:n-1-floor((rownum-1)/:n)
  43.   from dual
  44.   connect by rownum <= :n*:n
  45. ),
  46. symmsrc(blockN,bit,symmtype) as (   -- 对称判断表, blockN 是方格位置,bit是 blockN所对应对称点的二进制数字,symmtype是对称方式,共有八种(包括原地??
  47.   select blockN, power(2,blockN   ),0 from symmtmp  -- type 0, self, no symm
  48.   union all select blockN, power(2,xx+yo*:n ),1 from symmtmp -- type 1,上下
  49.   union all select blockN, power(2,xo+yy*:n ),2 from symmtmp -- type 2,左右
  50.   union all select blockN, power(2,yo+xo*:n ),3 from symmtmp -- type 3,对角
  51.   union all select blockN, power(2,yy+xx*:n ),4 from symmtmp -- type 4,反对角
  52.   union all select blockN, power(2,yo+xx*:n ),5 from symmtmp -- type 5,顺时针 90
  53.   union all select blockN, power(2,xx+yy*:n ),6 from symmtmp -- type 6,顺时针 180
  54.   union all select blockN, power(2,yy+xo*:n ),7 from symmtmp -- type 7,顺时针 270
  55. ),
  56. solution_symm as (
  57.   select /*+ materialize use_hash(symmsrc solution2) ordered */ solutionStrings,sum(bit) bitSum--,symmtype
  58.   -- 去除对称重复结果第一步, 得出每个solution对应的对称结果的二进制数据 .
  59.   from symmsrc,solution2
  60.   where substr(solutionStrings,blockN+1,1)='1'
  61.   group by solutionStrings,symmtype
  62. )
  63. select * from
  64. (select :m m, :n n,count(distinct bitSum) "AllCnt" from solution_symm), --这里把前面过滤掉的左右对称部分找回来 .
  65. (select  count(distinct min(bitSum)) "NoReptCnt" from solution_symm group by solutionStrings)

复制代码

[ 本帖最后由 rollingpig 于 2011-3-30 12:29 编辑 ]

使用道具 举报

回复
论坛徽章:
69
奥运会纪念徽章:射击
日期:2016-09-06 23:08:25马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:112013年新春福章
日期:2013-02-25 14:51:24复活蛋
日期:2013-02-18 11:25:01迷宫蛋
日期:2012-12-25 17:17:41复活蛋
日期:2012-12-21 17:41:38奥运会纪念徽章:沙滩排球
日期:2012-10-27 14:59:31ITPUB 11周年纪念徽章
日期:2012-10-09 18:03:32
12#
发表于 2011-3-29 20:11 | 只看该作者

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
13#
发表于 2011-3-29 20:30 | 只看该作者
有扎实的DBA基础的滚珠,写SQL代码时极尽一切调优手段,性能想不高都难

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
14#
发表于 2011-3-29 21:48 | 只看该作者
构造symmsrc的思路真是令人叹为观止,读这种程序是很享受的。
但我还是更喜欢TRANSLATE的方法,效率更高(symmsrc里面有N*N*8行),受ORACLE的NUMBER精度限制,BIT的表现力只能做到N=11.

使用道具 举报

回复
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
15#
 楼主| 发表于 2011-3-30 11:00 | 只看该作者
嗯。
对于我来说,translate的方式当时是想不到的。
说实话,直到看到答案之前,我还不知道translate还有带3个参数的做法。

另外,看了一下人肉和你创建translate穿的做法,似乎有一个更为简单的写法。



  1. var n number
  2. exec :n:=10;
  3. with symmtmp(blockN,xo,yo,xx,yy) as (  --base table for  对称判断.
  4.   select /*+ materialize */  
  5. rownum-1 ,mod(rownum-1,:n),floor((rownum-1)/:n)  ,
  6. :n-1-mod(rownum-1,:n),:n-1-floor((rownum-1)/:n)
  7.   from dual
  8.   connect by rownum <= :n*:n
  9. ), symmsrc(block_org,block_new,symmtype) as (   -- 对称判断表, blockN 是方格位置,bit是 blockN所对应对称点的二进制数字,symmtype是对称方式,共有八种(包括原地??
  10.   select blockN, blockN ,0 from symmtmp  -- type 0, self, no symm
  11.   union all select blockN, xx+yo*:n ,1 from symmtmp -- type 1,上下
  12.   union all select blockN, xo+yy*:n ,2 from symmtmp -- type 2,左右
  13.   union all select blockN,yo+xo*:n ,3 from symmtmp -- type 3,对角
  14.   union all select blockN, yy+xx*:n ,4 from symmtmp -- type 4,反对角
  15.   union all select blockN, yo+xx*:n ,5 from symmtmp -- type 5,顺时针 90
  16.   union all select blockN, xx+yy*:n ,6 from symmtmp -- type 6,顺时针 180
  17.   union all select blockN, yy+xo*:n ,7 from symmtmp -- type 7,顺时针 270
  18. ) ,
  19. symm_string as (
  20. select MAX(DECODE(symmtype,0,replace(r,'!'))) tpl0
  21.       ,MAX(DECODE(symmtype,1,replace(r,'!'))) tpl1
  22.       ,MAX(DECODE(symmtype,2,replace(r,'!'))) tpl2
  23.       ,MAX(DECODE(symmtype,3,replace(r,'!'))) tpl3
  24.       ,MAX(DECODE(symmtype,4,replace(r,'!'))) tpl4
  25.       ,MAX(DECODE(symmtype,5,replace(r,'!'))) tpl5
  26.       ,MAX(DECODE(symmtype,6,replace(r,'!'))) tpl6
  27.       ,MAX(DECODE(symmtype,7,replace(r,'!'))) tpl7  
  28. from(
  29.     select sys_connect_by_path(chr(block_new+ascii('!')+1),'!')  r ,level as l,symmtype
  30.     from symmsrc start with block_org=0 connect by  prior block_org+1  = block_org and prior symmtype = symmtype
  31. )
  32. where l = :n*:n )
  33. select * from symm_string


复制代码
原帖由 newkid 于 2011-3-29 21:48 发表
构造symmsrc的思路真是令人叹为观止,读这种程序是很享受的。
但我还是更喜欢TRANSLATE的方法,效率更高(symmsrc里面有N*N*8行),受ORACLE的NUMBER精度限制,BIT的表现力只能做到N=11.

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
16#
发表于 2011-3-30 11:27 | 只看该作者
我看了一下其实大同小异,你写得紧凑些,我的行列转换多了一层,因为中间那一层我后面有用(还原所有解法)。
这几个模版怎么折腾,复杂性都有限,开销可以忽略。

使用道具 举报

回复
论坛徽章:
33
劳斯莱斯
日期:2013-08-08 14:01:23三菱
日期:2013-09-28 10:16:06一汽
日期:2013-11-19 17:01:11凯迪拉克
日期:2013-12-07 17:11:282014年新春福章
日期:2014-02-18 16:42:02马上有房
日期:2014-02-18 16:42:02itpub13周年纪念徽章
日期:2014-09-27 14:20:21itpub13周年纪念徽章
日期:2014-10-08 15:13:38懒羊羊
日期:2015-03-04 14:52:112015年新春福章
日期:2015-03-06 11:58:18
17#
发表于 2011-3-30 11:46 | 只看该作者
只有看的份

使用道具 举报

回复
论坛徽章:
44
双鱼座
日期:2016-01-07 20:57:31奔驰
日期:2013-08-02 22:22:552013年新春福章
日期:2013-02-25 14:51:24迷宫蛋
日期:2013-01-29 22:12:11蛋疼蛋
日期:2013-01-07 15:50:53ITPUB十周年纪念徽章
日期:2011-11-01 16:20:28紫蛋头
日期:2011-07-31 11:27:01蜘蛛蛋
日期:2011-06-14 14:20:33蛋疼蛋
日期:2011-06-03 19:39:27SQL大赛参与纪念
日期:2011-04-13 12:08:17
18#
发表于 2011-3-30 12:11 | 只看该作者
from linesrc  
  where line>reverse(line)  --预先过滤左右对称
  union all
大师笔误,应该是  where line>=reverse(line)

使用道具 举报

回复
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
19#
 楼主| 发表于 2011-3-30 12:52 | 只看该作者
里面多了一步去除字符list中0,1,分隔符. 实际上里面不需要特意去0,1,不会影响translate的结果。当然,我的分隔符实际上也是去的,不过是直接通过从分隔符+1开始拼字符串来去掉的。

如果担心因此影响N的取值,也有办法轻松绕过。


  1. with
  2. linesrc(line,linenum) as (   -- 生成 01010串
  3.       select replace(linestr,',') line ,to_number(replace(linestr,','))
  4.     from (
  5.       select sys_connect_by_path(bit,',') linestr,level LevelN
  6.       from (
  7.         select 0 bit from dual
  8.         union all
  9.         select 1 from dual
  10.       )
  11.       connect by level <= :n
  12.     )where LevelN=:n
  13.   and length(linestr)-length(replace(linestr,1))=:m     -- 每行正好m个球.
  14. ),
  15. solution(LevelN ,solutionStrings, cmp1,cmp2,cmp3 ) as (
  16.   select
  17.      1 --LevelN
  18.     ,line -- solutionStrings
  19.     ,linenum
  20.     ,linenum
  21.     ,linenum * power(10,:n-1)
  22.   from linesrc  
  23.   where line>=reverse(line)  --预先过滤左右对称
  24.   union all
  25.   select
  26.     LevelN +1  
  27.     ,solutionStrings || line
  28.     ,cmp1+linenum     
  29.     ,cmp2+linenum*power(10,levelN)     
  30.     ,cmp3+linenum*power(10,:n-levelN-1)     
  31.   from solution,linesrc     
  32.   where
  33.   levelN<:n and
  34.   instr((cmp1+linenum ) || ( cmp2+linenum*power(10,levelN))  || (cmp3+linenum*power(10,:n-levelN-1)) ,:m+1 ) =0
  35. ),
  36. solution2(solutionStrings) as(  -- original solution
  37.   select /*+ materialize */  solutionStrings from   solution
  38.   where LevelN=:n
  39. ),
  40. symmtmp(blockN,xo,yo,xx,yy) as (  --base table for  对称判断.
  41.   select /*+ materialize */  
  42. rownum-1 ,mod(rownum-1,:n),floor((rownum-1)/:n)  ,
  43. :n-1-mod(rownum-1,:n),:n-1-floor((rownum-1)/:n)
  44.   from dual
  45.   connect by rownum <= :n*:n
  46. ), symmsrc(block_org,block_new,symmtype) as (   -- 对称判断表, blockN 是方格位置,bit是 blockN所对应对称点的二进制数字,symmtype是对称方式,共有八种(包括原地??
  47.   select blockN, blockN ,0 from symmtmp  -- type 0, self, no symm
  48.   union all select blockN, xx+yo*:n ,1 from symmtmp -- type 1,左右
  49.   union all select blockN, xo+yy*:n ,2 from symmtmp -- type 2,上下
  50.   union all select blockN,yo+xo*:n ,3 from symmtmp -- type 3,对角
  51.   union all select blockN, yy+xx*:n ,4 from symmtmp -- type 4,反对角
  52.   union all select blockN, yo+xx*:n ,5 from symmtmp -- type 5,顺时针 90
  53.   union all select blockN, xx+yy*:n ,6 from symmtmp -- type 6,顺时针 180
  54.   union all select blockN, yy+xo*:n ,7 from symmtmp -- type 7,顺时针 270
  55. ) ,
  56. symm_string as (
  57. select MAX(DECODE(symmtype,0,replace(r,'!'))) tpl0
  58.       ,MAX(DECODE(symmtype,1,replace(r,'!'))) tpl1
  59.       ,MAX(DECODE(symmtype,2,replace(r,'!'))) tpl2
  60.       ,MAX(DECODE(symmtype,3,replace(r,'!'))) tpl3
  61.       ,MAX(DECODE(symmtype,4,replace(r,'!'))) tpl4
  62.       ,MAX(DECODE(symmtype,5,replace(r,'!'))) tpl5
  63.       ,MAX(DECODE(symmtype,6,replace(r,'!'))) tpl6
  64.       ,MAX(DECODE(symmtype,7,replace(r,'!'))) tpl7  
  65. from(
  66.     select sys_connect_by_path(chr(block_new+ascii('!')+1),'!')  r ,level as l,symmtype
  67.     from symmsrc start with block_org=0 connect by  prior block_org+1  = block_org and prior symmtype = symmtype
  68. )
  69. where l = :n*:n )
  70. select * from
  71. (select :m M,:n n,
  72. count(distinct least(
  73.     SOLUTIONSTRINGS
  74.     ,TRANSLATE(tpl1,tpl0,SOLUTIONSTRINGS)
  75.     ,TRANSLATE(tpl2,tpl0,SOLUTIONSTRINGS)
  76.     ,TRANSLATE(tpl3,tpl0,SOLUTIONSTRINGS)
  77.     ,TRANSLATE(tpl4,tpl0,SOLUTIONSTRINGS)
  78.     ,TRANSLATE(tpl5,tpl0,SOLUTIONSTRINGS)
  79.     ,TRANSLATE(tpl6,tpl0,SOLUTIONSTRINGS)
  80.     ,TRANSLATE(tpl7,tpl0,SOLUTIONSTRINGS)
  81. )) as noReptCnt from symm_string,solution2),
  82. (select count(distinct SOLUTIONSTRINGS) as all_cnt from (
  83. select SOLUTIONSTRINGS from symm_string,solution2
  84. union  select translate(tpl0,tpl1,SOLUTIONSTRINGS) from symm_string,solution2
  85. ))

复制代码


原帖由 newkid 于 2011-3-30 11:27 发表
我看了一下其实大同小异,你写得紧凑些,我的行列转换多了一层,因为中间那一层我后面有用(还原所有解法)。
这几个模版怎么折腾,复杂性都有限,开销可以忽略。

使用道具 举报

回复
论坛徽章:
131
2006年度最佳技术回答
日期:2007-01-24 12:58:48福特
日期:2013-10-24 13:57:422014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11马上有车
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有对象
日期:2014-02-19 11:55:14马上加薪
日期:2014-02-19 11:55:142013年新春福章
日期:2013-02-25 14:51:24
20#
 楼主| 发表于 2011-3-30 12:52 | 只看该作者
改过来了
原帖由 mychary 于 2011-3-30 12:11 发表
from linesrc  
  where line>reverse(line)  --预先过滤左右对称
  union all
大师笔误,应该是  where line>=reverse(line)

使用道具 举报

回复

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

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表