楼主: tree_new_bee

Euler Project 挨个做- 之二 (Q51-Q78)

[复制链接]
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
61#
发表于 2011-1-2 11:21 | 只看该作者
我运行了scala的代码,没什么优化 Q58很快,不到2秒,看来语言有时候真的很重要

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
62#
 楼主| 发表于 2011-1-2 15:59 | 只看该作者
原帖由 〇〇 于 2011-1-2 11:21 发表
我运行了scala的代码,没什么优化 Q58很快,不到2秒,看来语言有时候真的很重要


这个我觉得倒不是由于scala语言的优势造成的。
而是因为oracle的mod函数特别低效造成的。

把我#55的代码中isprim换成java版本的isprimj (两个版本算法基本相同), 只要4.2秒。
如果全部都在java中来实现, 估计也应该与scala中的时间差不多。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
63#
 楼主| 发表于 2011-1-2 16:18 | 只看该作者
原帖由 〇〇 于 2011-1-1 22:19 发表
tnb请把工具包放在1楼啊,便于学习..


放上去了。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
64#
 楼主| 发表于 2011-1-2 17:00 | 只看该作者
Q59与其说是考验代码技巧, 不如说是考验对什么叫"普通英语文本"的常识。

先来一段笨拙的plsql代码, 这里对"普通英语"的认定, 是认为字母+空格应该占据全部字符的90%以上。

因为密文只有3k, 可以放到一个字符串中, 所以不再单独考虑读文件的环节。

declare
  i integer;
  cryptstr constant varchar2(4000)   :='79,59,12,2,79,35,8,28,20,以下略。。。' ;
  numlist t_numlist := new t_numlist();
  tmpstr varchar2(4000);
  c number;
  success boolean;
  newc number;
  newstr varchar2(4000);
  alpha number;
  sm number;
function xor(x IN NUMBER,y IN NUMBER) return number is
begin
         return (x + y) - BITAND(x, y)- BITAND(x, y);
end;

begin
  tmpstr:= cryptstr||',';
  while tmpstr is not null loop
      numlist.extend;
      numlist(numlist.count) := substr(tmpstr, 1, instr(tmpstr,',')-1);
      tmpstr := substr(tmpstr, instr(tmpstr,',')+1);            
  end loop;

  for c1 in 97..122 loop
  for c2 in 97..122 loop
  for c3 in 97..122 loop
      newstr:='';
      success := true;
      alpha:=0;
      sm:=0;
      for i in 1.. numlist.count loop
        c := case mod(i,3) when 1 then c1 when 2 then c2 when 0 then c3 end;
        PRAGMA INLINE(XOR, 'YES');
        newc := xor(numlist(i), c);
        if newc <32 or newc> 126 then
         success:=false;
         exit;
        end if;
        if (newc = 32) or (newc between 65 and 90) or (newc between 97 and 122 )then
          alpha := alpha+1;
        end if;
        sm := sm+newc;
        newstr:=newstr||chr(newc);        
      end loop;   
      if success and alpha/numlist.count > 0.9 then
           dbms_output.put_line('key:'||chr(c1)||chr(c2)||chr(c3));
           dbms_output.put_line('newstr:'||newstr);
           dbms_output.put_line('sum:'||sm);
      end if;
  end loop;
  end loop;
  end loop;
end;

key:god
newstr: (The Gospel of John, chapter 1) 1 In the beginning ................................
sum:107359

PL/SQL procedure successfully completed

Executed in 5.468 seconds

SQL>

[ 本帖最后由 tree_new_bee 于 2011-1-2 18:35 编辑 ]

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
65#
发表于 2011-1-2 17:20 | 只看该作者
Q58 PLSQL版本
没什么优化的比tnb的sql+函数版本还慢

  1. create or replace procedure Q58
  2. as
  3. side number:=3;
  4. numbers number:=1;
  5. primes number:=0;
  6. percentage number:=100;

  7. function is_prime(n number)
  8. return number
  9. as
  10. i number:=3;
  11. begin
  12.    while i<=sqrt(n) LOOP
  13.    if mod(n,i)=0 then
  14.            return 0;
  15.    end if;
  16.    i:=i+2;
  17.    end loop;
  18.    return 1;
  19. end;

  20. begin
  21. while percentage>=10  loop
  22.       numbers:=numbers+4;
  23.       if is_prime(side*side)=1 then primes:=primes+1;end if;
  24.       if is_prime(side*side-side+1)=1 then primes:=primes+1;end if;
  25.       if is_prime(side*side-2*side+2)=1 then primes:=primes+1;end if;
  26.       if is_prime(side*side-3*side+3)=1 then primes:=primes+1;end if;
  27.       percentage:=(100*primes)/numbers;
  28.       /* printf("%d %d\n",side,percentage);*/
  29.       side:=side+2;
  30. end loop;
  31. dbms_output.put_line(side-2);
  32. end;
  33. /   
复制代码


  1. create or replace procedure Q58b
  2. as
  3. side number:=3;
  4. numbers number:=1;
  5. primes number:=0;
  6. percentage number:=100;
  7.   TYPE t_row IS TABLE OF BINARY_INTEGER;
  8.   V_RESULT T_row:=t_row();

  9. PROCEDURE NEWKIDI(X IN NUMBER) AS --newkid改写的筛法求质数,利用v_result.DELETE删除合数
  10.   I NUMBER DEFAULT 1;
  11.   J NUMBER DEFAULT 0;
  12.   C NUMBER DEFAULT 1;
  13.   lv_limit NUMBER := x;
  14.   lv_upper1 NUMBER := (SQRT(lv_limit)-1)/2;
  15.   lv_upper2 NUMBER := lv_limit/2-1;
  16.   lv_step BINARY_INTEGER;
  17. BEGIN
  18.     v_result.EXTEND(lv_upper2);
  19.     while i<lv_upper1 loop
  20.           lv_step := i*2+1;
  21.           j:=2*i*(i+1);
  22.           while j<=lv_upper2 loop
  23.                 v_result.DELETE(j);
  24.                 j:=j+lv_step;
  25.           end loop;
  26.           i := v_result.NEXT(i);
  27.     end loop;
  28. --DBMS_OUTPUT.PUT_LINE(v_result.COUNT+1); -- 把2算进去
  29. END;

  30. function is_prime(n number)
  31. return number
  32. as
  33. i number:=1;
  34. begin
  35.    if n in(2,3,5,7) then return 1; end if;
  36.    while i*2+1<=sqrt(n) LOOP
  37.    if mod(n,i*2+1)=0 then
  38.            return 0;
  39.    end if;
  40.    i:=v_result.NEXT(i);
  41.    end loop;
  42.    return 1;
  43. end;

  44. begin
  45. NEWKIDI(100000);       
  46. while percentage>=10  loop
  47.       numbers:=numbers+4;
  48.       if is_prime(side*side)=1 then primes:=primes+1;end if;
  49.       if is_prime(side*side-side+1)=1 then primes:=primes+1;end if;
  50.       if is_prime(side*side-2*side+2)=1 then primes:=primes+1;end if;
  51.       if is_prime(side*side-3*side+3)=1 then primes:=primes+1;end if;
  52.       percentage:=(100*primes)/numbers;
  53.       side:=side+2;
  54. end loop;
  55. dbms_output.put_line(side-2);
  56. end;
  57. /   
复制代码


SQL> @d:\app\q58

过程已创建。

已用时间:  00: 00: 00.02
SQL> exec q58
26241

PL/SQL 过程已成功完成。

已用时间:  00: 00: 34.77
SQL> @d:\app\q58b

过程已创建。

已用时间:  00: 00: 00.06
SQL> exec q58b
26241

PL/SQL 过程已成功完成。

已用时间:  00: 00: 13.42

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
66#
发表于 2011-1-2 18:08 | 只看该作者
比较了下tnb和newkid的筛法产生质数函数,貌似有差距,但不知道是否因为复制到外部造成的
SQL> select count(*) from table(pkg_prim2.seive_numlist(1000000));

  COUNT(*)
----------
     78498

已用时间:  00: 00: 01.23
SQL> /

  COUNT(*)
----------
     78498

已用时间:  00: 00: 01.22

  1. CREATE OR REPLACE PROCEDURE NEWKIDI(X IN NUMBER) AS --newkid改写的筛法求质数,利用v_result.DELETE删除合数
  2.   TYPE t_row IS TABLE OF BINARY_INTEGER;
  3.   V_RESULT T_row:=t_row();
  4.   I NUMBER DEFAULT 1;
  5.   J NUMBER DEFAULT 0;
  6.   C NUMBER DEFAULT 1;
  7.   lv_limit NUMBER := x;
  8.   lv_upper1 NUMBER := (SQRT(lv_limit)-1)/2;
  9.   lv_upper2 NUMBER := lv_limit/2-1;
  10.   lv_step BINARY_INTEGER;
  11. BEGIN
  12.     v_result.EXTEND(lv_upper2);
  13.     while i<lv_upper1 loop
  14.           lv_step := i*2+1;
  15.           j:=2*i*(i+1);
  16.           while j<=lv_upper2 loop
  17.                 v_result.DELETE(j);
  18.                 j:=j+lv_step;
  19.           end loop;
  20.           i := v_result.NEXT(i);
  21.     end loop;
  22. DBMS_OUTPUT.PUT_LINE(v_result.COUNT+1); -- 把2算进去
  23. j:=1;
  24. /*
  25. for i in 1..v_result.COUNT loop
  26. DBMS_OUTPUT.PUT_LINE(j*2+1);
  27. j:=v_result.next(j);       
  28. end loop;
  29. */
  30. END;
  31. /
复制代码

过程已创建。

已用时间:  00: 00: 00.02
SQL> exec newkidi(1000000)
78498

PL/SQL 过程已成功完成。

已用时间:  00: 00: 00.34
SQL>

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
67#
 楼主| 发表于 2011-1-2 18:19 | 只看该作者
原帖由 〇〇 于 2011-1-2 18:08 发表
比较了下tnb和newkid的筛法产生质数函数,貌似有差距,但不知道是否因为复制到外部造成的


不是。
是因为我额外的多执行了几次遍历数组的循环。
另外, seive_numlist和seive_indextable两个为了共享一段代码, 也增添了一些额外的开销。

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
68#
发表于 2011-1-2 18:32 | 只看该作者
加上了输出确实还是newkid的快

  1. create or replace  FUNCTION seive_numlist(maxnum NUMBER) RETURN t_numlist IS
  2.     i      INTEGER;
  3.     RESULT t_numlist := NEW t_numlist();
  4.   TYPE t_row IS TABLE OF BINARY_INTEGER;
  5.   V_RESULT T_row:=t_row();
  6.     PROCEDURE NEWKID(X IN NUMBER) AS --newkid改写的筛法求质数,利用v_result.DELETE删除合数
  7.   I NUMBER DEFAULT 1;
  8.   J NUMBER DEFAULT 0;
  9.   C NUMBER DEFAULT 1;
  10.   lv_limit NUMBER := x;
  11.   lv_upper1 NUMBER := (SQRT(lv_limit)-1)/2;
  12.   lv_upper2 NUMBER := lv_limit/2-1;
  13.   lv_step BINARY_INTEGER;
  14. BEGIN
  15.     v_result.EXTEND(lv_upper2);
  16.     while i<lv_upper1 loop
  17.           lv_step := i*2+1;
  18.           j:=2*i*(i+1);
  19.           while j<=lv_upper2 loop
  20.                 v_result.DELETE(j);
  21.                 j:=j+lv_step;
  22.           end loop;
  23.           i := v_result.NEXT(i);
  24.     end loop;
  25. --DBMS_OUTPUT.PUT_LINE(v_result.COUNT+1); -- 把2算进去
  26. end;
  27.   BEGIN
  28.     newkid(maxnum);
  29.       result.extend(v_result.COUNT+1);
  30.       result(1):=2;
  31.       i:=1;
  32.      for j in 2..result.COUNT loop
  33.        RESULT(j) := i*2+1;
  34.       i := v_result.next(i);
  35.     END LOOP;
  36.     RETURN RESULT;
  37.   END;
  38. /
复制代码

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
69#
 楼主| 发表于 2011-1-2 18:44 | 只看该作者
继续解59题。
#64对"普通英语文本"的认定, 是认为字母+空格应该占据全部字符的90%以上。 这种做法比较低效。
更好的认定方法是: 在正常的英语文本中, 数量最多的是空格, 并且这种多是绝对性的多, 在任何较长的片段都是最多的, 甚至几十按照隔几个挑一个字符的方法, 挑出来的字符串中也一定是空格最多。
因此, 我们可以从1/4/7... 的字符中找出最多的,假定它是空格, 然后破解对应的key,  再 2/5/8... 和3/6/9...中同样的方法找出第二个第三个key

用这样的方法, 甚至不需要题目给出的条件: 3个"小写字母"。

这次纯粹用SQL来解决, 虽然写的依然是冗长了一些:

with t as (select '79,59,12,2,79,35,8,28,20,2,以下略。。。。。。' str
from dual)
,t1 as (select cast(','||str||',' as varchar2(4000)) str from t)
,td as (select rownum d from t1 connect by rownum<=length(translate(str, ','||str, ',')) )
,tall as (select /*+ MATERIALIZE */ d, instr(str, ',', 1,d), instr(str, ',', 1,d+1)-1,
      substr(str, instr(str, ',',1, d)+1,instr(str, ',', 1,d+1)-instr(str, ',', 1,d)-1) crypt
      from t1,td where d<length(translate(str, ','||str, ',')))
,tchar as (select level c from dual where level>=97 connect by level<=122)
,tspace as (select mod(d,3) seq ,crypt,count(*) cnt from tall group by  mod(d,3),crypt)
,tspace2 as (select seq, substr(max(to_char(cnt, 'FM0000')||crypt),5) sp from tspace  group by seq)
,tkey as (select seq, (sp+32) - BITAND(sp,32)*2 key from tspace2 )
,tdecrypt as (select d, (crypt + key) - BITAND(crypt, key) * 2 decrypt
from tall, tkey where mod(d,3)=seq)
select sum(decrypt) from tdecrypt


SUM(DECRYPT)
------------
      107359

Executed in 2.187 seconds


其中tspace2的写法,是刚刚从http://www.itpub.net/thread-1383362-1-1.html 贴子里,newkid那里偷来的。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
70#
 楼主| 发表于 2011-1-2 19:06 | 只看该作者
原帖由 〇〇 于 2011-1-2 18:32 发表
加上了输出确实还是newkid的快


仔细看了看, 原来newkid在循环的时候,使用了已有的筛查结果, 所以效率会高很多。
另外, 按照奇数的序号来处理, 节省了一半数组维护操作的开销。 newkid装修大师写出的东西真的是精干到了极致。

把测试数据从100万加到500万, newkid的函数运行时间增加了5倍, 已经基本上近似线性关系了。


"加上了输出确实还是newkid的快",  在输出时,结果集已经很小了,那个时候对数组的扩展已经相比整体性能已经可以忽略了。


我的工具库里的装备又升级了。

[ 本帖最后由 tree_new_bee 于 2011-1-3 00:44 编辑 ]

使用道具 举报

回复

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

本版积分规则 发表回复

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