復活節最短原始碼分析
題目:
本週日,也就是4月24日,是今年的復活節,復活節(Easter),是紀念耶穌基督復活的節日,西方信基督教的國家都過這個節。
復活節的日期是不固定的在西方教會傳統裡,春分之後第一次滿月之後的第一個星期日即為復活節。東方教會則規定,如果滿月恰逢星期日,則復活節再推遲一週。 因此,節期大致在3月22日至4月25日之間。復活節是最古老最有意義的基督教節日之一,慶祝的是基督的復活,世界各地的基督徒每年都要舉行慶祝。
節日的演算法也不勞大家去找了
現在提出比賽要求:
##############################################################
本來提交的人不多,到後來每個選手的位元組數也越來越少,我的應該是1500位元組以內最多的了,不過在野花版主的鼓勵下,決定還是寫一寫。
解題分析:
1、所有型別都以varchar2(99)替代,包括int型別的轉換,都是用Oracle內部的轉換實現,使得所有型別都只以一個字元表達。
2、列印封裝為一個P函式
3、初始化時,做以下事情:
3.1、將所有復活節都以“yyyy mm-dd”方式儲存在陣列v中,陣列v在package初始化時載入
3.2、獲取所有復活節在4月1日的年份,放入陣列r中
3.3、將每個日期最大的出現次數儲存在陣列u中,陣列以mm-dd為索引,存放相應出現的次數
3.4、將三月份、四月份以總共出現的次數最高的次數放到變數m/n/q中
4、列印:
4.1、showAllEasterDay:列印v陣列。
4.2、showMaxOccurenceEasterDay:從陣列u中輪詢,將每個日期出現次數為q/m/n的日期分別拼接起來,列印最終的字串d/e/f即相應的次數q/m/n。
4.3、showLeapEasterDay:這個是要列印沒有在指定區間的出現過的日期,如果是連續的則要求只輸出開始日期和結束日期。一開始很自然的想到了野花的連續號段處理,但是得用sql來實現。我想了下,預計用sql實現會比較長,所以直接考慮用pl/sql來實現。
----------------------------------------------------------------------
我的演算法(位元組長度1442)
----------------------------------------------------------------------
首先,我們知道,要列印的是一個開始時間和一個結束時間,如果只有一天,則結束時間=開始時間,所以先定義這兩個變數。
然後,得到要求區間所有的日期(也就是3.22-4.25),透過 1 .. date'1-4-25' - date'1-3.22'+1,輪詢每個日期。
再給定一個標識,指定如果當前日期在陣列中存在,則標識0,如果不存在,則標識1,然後到下一條記錄的時候,首先判斷當前日期是否存在於陣列中:
A> 如果不存在,則將結束日期置為當前日期,並判斷標識是否為0,如果為0,則將開始日期也置為當前日期。並將標識置為1。
B> 如果存在,則判斷標識是否為1,如果為1,則說明上個日期是出現在陣列中的,所以要列印開始和結束日期。然後將標識置為0。
可能邏輯說明有點枯燥,舉個例子吧:
比如說,有以下日期列表:
日期 是否存在陣列中(1表示不存在,因為實際要列印的是不存在的日期)
3.22 1 --此時3.22不在陣列中,所以置開始日期和結束日期為3.22,由於變數標
識flag初始化為0,所以此時不列印,然後置flag=1;
3.23 0 --此時3.23在陣列中,開始日期和結束日期還是3.22,但是此時flag=1,
所以此時列印,並置flag=0;
3.24 0 --此時3.23在陣列中,開始日期和結束日期還是3.22,但是此時flag=0,
所以此時不列印,並置flag=0;
3.25 1 --此時3.25不在陣列中,開始日期和結束日期被置為3.25,並且flag=0,
所以此時不列印,並置flag=1;
3.26 1 --此時3.26不在陣列中,開始日期仍為3.25,結束日期被置為3.26,此時
flag=1,所以此時仍不列印,並置flag=1;
3.27 1 --此時3.27不在陣列中,開始日期仍為3.25,結束日期被置為3.27,並且
flag=1,所以此時仍不列印,並置flag=1;
3.28 0 --此時3.28在陣列中,開始日期為3.25,結束日期為3.27,且flag=1,所
以此時列印開始和結束日期,並置flag=0;
也就是每次滿足存在陣列中,而且上次存在標識為不存在,則列印變數中的開始和結束日期。
如果不存在陣列中,則輪詢第一次首先將開始日期和結束日期置為當前輪詢日期,然後接下去日期還不存在於陣列中,則將結束日期置為當前日期,開始日期不變。直到輪詢到日期存在為止,然後按上個步驟判斷是否列印。
特殊情況:當結束日期直到超過4.25時,還沒有出現存在的日期,就直接列印開始和結束日期。
4.4、showFoolEasterDay:列印r陣列即可。
程式碼:
create or replace package body easter as
subtype w is varchar2(99);
type s is table of w index by w;
u s;
r s;
v s;
t w;
q w := 0;
m w := 0;
n w := 0;
a w;
b w;
c w;
d w;
e w;
f w := 1900;
procedure p(a w)as begin dbms_output.put_line(a); end;
procedure showAllEasterDay as
begin
p('YEAR DAY');
for i in 1 .. v.count loop
p(v(i));
end loop;
end;
procedure showMaxOccurenceEasterDay as
d w;
e w;
f w;
begin
a := u.first;
while a is not null loop
b := u(a);--取每個日期的出現次數
if b = q then --當該日期出現次數為最大出現次數時
d := d || '/' || a;--將符合要求的日期拼接到字串中
end if;
if a like '03%' and b = m then--三月份出現最多的
e := e || '/' || a;
elsif b = n then--除了三月份,就是四月份了
f := f || '/' || a;
end if;
a := u.next(a);
end loop;
--列印時,沒去掉第一個/符號
p('MAXOCC MO_CNT MAXOCC_3 MO3_CNT MAXOCC_4 MO4_CNT ');
p(d || ' ' || q || ' ' ||
e || ' ' || m || ' ' ||
f || ' ' || n);
end;
procedure showLeapEasterDay as
begin
f := 0;
p('ABSENT_START ABSENT_END');
for i in 0 .. date'1-4-25' - date'1-3-22' + 1 loop
a := to_char(date'1-3-22' + i, 'mm-dd');
if u.exists(a) then--日期存在
if f = 1 then
p(b || ' ' || e);--上次不存在則列印
end if;
f := 0;--置本次存在標識為0,即存在
else
e := a;--結束日期=當前日期
if f = 0 then
b := a;--如果上次存在,則開始日期=當前日期
end if;
if a = '04-25' then--到4.25還沒有存在的日期就直接列印
p(b || ' ' || e);
end if;
f := 1;--置存在標識為1,即不存在
end if;
end loop;
end;
procedure showFoolEasterDay as
begin
p('YEAR TOTAL');
for i in 1 .. r.count loop
p(r(i) || ' ' || t);
end loop;
end;
begin
u.delete;
t := 0;
for i in f .. 2099 loop
d := i - f;
a := d mod 19;
c := (11 * a + 4 - trunc((7 * a + 1)/19)) mod 29;
b := 25-c-mod(d + trunc(d/4) + 31 - c, 7);
if b > 0
then a := '04'; c := b;
else a := '03'; c := 31+b;
end if;
c := lpad(c,2,0);
b := a||'-'||c;
v(d+1) := i || ' ' || b;
if b = '04-01' then t := t + 1; r(t) := i; end if;
if u.exists(b) then
e := u(b) + 1;--累計每個日期的出現次數
q := greatest(e,q);--取最大次數演算法
if b like '03%' then--取三月份最大次數演算法
m := greatest(e,m);
else--四月份最大次數演算法
n := greatest(e,n);
end if;
else e := 1;
end if;
u(b) := e;
end loop;
end;
/
最後,為了照顧到程式碼的完整性,可以將開始年份和結束年份變成以引數輸入。這個就不再貼出程式碼了,改動很簡單。
本週日,也就是4月24日,是今年的復活節,復活節(Easter),是紀念耶穌基督復活的節日,西方信基督教的國家都過這個節。
復活節的日期是不固定的在西方教會傳統裡,春分之後第一次滿月之後的第一個星期日即為復活節。東方教會則規定,如果滿月恰逢星期日,則復活節再推遲一週。 因此,節期大致在3月22日至4月25日之間。復活節是最古老最有意義的基督教節日之一,慶祝的是基督的復活,世界各地的基督徒每年都要舉行慶祝。
節日的演算法也不勞大家去找了
QUOTE:
現在有一個簡便的演算法供大家參考!
年份只限於1900年到2099年
1 設要求的那一年是Y年,從Y減去1900,其差記為N。
2 用19作除數去除N,餘數記為A。
3 用4作除數去除N,不管餘數,把商記為Q。
4 用19去除7A+1,把商記為B,不管餘數。
5 用29去除11A+4-B,餘數記為M。
6 用7去除N+Q+31-M,餘數記為W。
7 計算25-M-W。
得出答數即可定出復活節的日期。若為正數,月份為4月,如為負數,月份為3月。若為0,則為3 月31日。
現在有一個簡便的演算法供大家參考!
年份只限於1900年到2099年
1 設要求的那一年是Y年,從Y減去1900,其差記為N。
2 用19作除數去除N,餘數記為A。
3 用4作除數去除N,不管餘數,把商記為Q。
4 用19去除7A+1,把商記為B,不管餘數。
5 用29去除11A+4-B,餘數記為M。
6 用7去除N+Q+31-M,餘數記為W。
7 計算25-M-W。
得出答數即可定出復活節的日期。若為正數,月份為4月,如為負數,月份為3月。若為0,則為3 月31日。
現在提出比賽要求:
- 用最短的程式碼,求出2011~2099之間的復活節,具體為:
- Q1:2011~2099之間每一年的復活節的具體日期
- Q2:2011~2099之間,幾月幾號出現得最多?3月出現得最多的是幾號?4月出現得最多的又是幾號?分別出現了多少次?
- Q3:2011~2099之間的復活節,3月22日至4月25日之間哪些日子沒有出現過?
- Q4:2011~2099之間“愚蛋節”的總次數,即4月1日同時又是復活節的總數量以及都在哪些年份出現。
- 答案要求用Package給出,package名為easter:
- package宣告為create or replace package easter
- Q1的宣告為procedure showAllEasterDay,無引數,輸出為一列表,形式如下所示:
YEAR DAY
2011 04-24
2012 04-08
………… - Q2的宣告為procedure showMaxOccurenceEasterDay,無引數,輸出為一行資料,日期後面跟著輸出出現的次數,如果是多個日期,則按從小到達,用“/”分隔顯示,形式如下所示:
MAXOCC MO_CNT MAXOCC_3 MO3_CNT MAXOCC_4 MO4_CNT
xx-xx x1 03-xx x2 04-xx/04-yy x3 - Q3的宣告為procedure showLeapEasterDay,無引數,連續未出現的日期用一行顯示,輸出為一列表,形式如下所示:
ABSENT_START ABSENT_END
03-22 03-25
04-02 04-02
04-11 04-22
………………(以上為示例資料,並非真實資料) - Q4的宣告為procedure showFoolEasterDay,無引數,輸出為一列表,形式如下所示(假設出現了n次):
YEAR TOTAL
yyyy1 n
yyyy2 n
…………
yyyyn n
- 包名和Q1~Q4的四個過程必須按約定給出,若需要在包中加入其他過程,請 自便,但需要注意,目標是原始碼位元組數最小哦!空格、TAB、CR、LF都不算位元組數,程式碼中不要包含註釋,註釋請寫在另外的檔案中,4月22日提交你的 結果,期間可在本帖隨意show你的程式碼的位元組數
##############################################################
本來提交的人不多,到後來每個選手的位元組數也越來越少,我的應該是1500位元組以內最多的了,不過在野花版主的鼓勵下,決定還是寫一寫。
解題分析:
1、所有型別都以varchar2(99)替代,包括int型別的轉換,都是用Oracle內部的轉換實現,使得所有型別都只以一個字元表達。
2、列印封裝為一個P函式
3、初始化時,做以下事情:
3.1、將所有復活節都以“yyyy mm-dd”方式儲存在陣列v中,陣列v在package初始化時載入
3.2、獲取所有復活節在4月1日的年份,放入陣列r中
3.3、將每個日期最大的出現次數儲存在陣列u中,陣列以mm-dd為索引,存放相應出現的次數
3.4、將三月份、四月份以總共出現的次數最高的次數放到變數m/n/q中
4、列印:
4.1、showAllEasterDay:列印v陣列。
4.2、showMaxOccurenceEasterDay:從陣列u中輪詢,將每個日期出現次數為q/m/n的日期分別拼接起來,列印最終的字串d/e/f即相應的次數q/m/n。
4.3、showLeapEasterDay:這個是要列印沒有在指定區間的出現過的日期,如果是連續的則要求只輸出開始日期和結束日期。一開始很自然的想到了野花的連續號段處理,但是得用sql來實現。我想了下,預計用sql實現會比較長,所以直接考慮用pl/sql來實現。
----------------------------------------------------------------------
我的演算法(位元組長度1442)
----------------------------------------------------------------------
首先,我們知道,要列印的是一個開始時間和一個結束時間,如果只有一天,則結束時間=開始時間,所以先定義這兩個變數。
然後,得到要求區間所有的日期(也就是3.22-4.25),透過 1 .. date'1-4-25' - date'1-3.22'+1,輪詢每個日期。
再給定一個標識,指定如果當前日期在陣列中存在,則標識0,如果不存在,則標識1,然後到下一條記錄的時候,首先判斷當前日期是否存在於陣列中:
A> 如果不存在,則將結束日期置為當前日期,並判斷標識是否為0,如果為0,則將開始日期也置為當前日期。並將標識置為1。
B> 如果存在,則判斷標識是否為1,如果為1,則說明上個日期是出現在陣列中的,所以要列印開始和結束日期。然後將標識置為0。
可能邏輯說明有點枯燥,舉個例子吧:
比如說,有以下日期列表:
日期 是否存在陣列中(1表示不存在,因為實際要列印的是不存在的日期)
3.22 1 --此時3.22不在陣列中,所以置開始日期和結束日期為3.22,由於變數標
識flag初始化為0,所以此時不列印,然後置flag=1;
3.23 0 --此時3.23在陣列中,開始日期和結束日期還是3.22,但是此時flag=1,
所以此時列印,並置flag=0;
3.24 0 --此時3.23在陣列中,開始日期和結束日期還是3.22,但是此時flag=0,
所以此時不列印,並置flag=0;
3.25 1 --此時3.25不在陣列中,開始日期和結束日期被置為3.25,並且flag=0,
所以此時不列印,並置flag=1;
3.26 1 --此時3.26不在陣列中,開始日期仍為3.25,結束日期被置為3.26,此時
flag=1,所以此時仍不列印,並置flag=1;
3.27 1 --此時3.27不在陣列中,開始日期仍為3.25,結束日期被置為3.27,並且
flag=1,所以此時仍不列印,並置flag=1;
3.28 0 --此時3.28在陣列中,開始日期為3.25,結束日期為3.27,且flag=1,所
以此時列印開始和結束日期,並置flag=0;
也就是每次滿足存在陣列中,而且上次存在標識為不存在,則列印變數中的開始和結束日期。
如果不存在陣列中,則輪詢第一次首先將開始日期和結束日期置為當前輪詢日期,然後接下去日期還不存在於陣列中,則將結束日期置為當前日期,開始日期不變。直到輪詢到日期存在為止,然後按上個步驟判斷是否列印。
特殊情況:當結束日期直到超過4.25時,還沒有出現存在的日期,就直接列印開始和結束日期。
4.4、showFoolEasterDay:列印r陣列即可。
程式碼:
create or replace package body easter as
subtype w is varchar2(99);
type s is table of w index by w;
u s;
r s;
v s;
t w;
q w := 0;
m w := 0;
n w := 0;
a w;
b w;
c w;
d w;
e w;
f w := 1900;
procedure p(a w)as begin dbms_output.put_line(a); end;
procedure showAllEasterDay as
begin
p('YEAR DAY');
for i in 1 .. v.count loop
p(v(i));
end loop;
end;
procedure showMaxOccurenceEasterDay as
d w;
e w;
f w;
begin
a := u.first;
while a is not null loop
b := u(a);--取每個日期的出現次數
if b = q then --當該日期出現次數為最大出現次數時
d := d || '/' || a;--將符合要求的日期拼接到字串中
end if;
if a like '03%' and b = m then--三月份出現最多的
e := e || '/' || a;
elsif b = n then--除了三月份,就是四月份了
f := f || '/' || a;
end if;
a := u.next(a);
end loop;
--列印時,沒去掉第一個/符號
p('MAXOCC MO_CNT MAXOCC_3 MO3_CNT MAXOCC_4 MO4_CNT ');
p(d || ' ' || q || ' ' ||
e || ' ' || m || ' ' ||
f || ' ' || n);
end;
procedure showLeapEasterDay as
begin
f := 0;
p('ABSENT_START ABSENT_END');
for i in 0 .. date'1-4-25' - date'1-3-22' + 1 loop
a := to_char(date'1-3-22' + i, 'mm-dd');
if u.exists(a) then--日期存在
if f = 1 then
p(b || ' ' || e);--上次不存在則列印
end if;
f := 0;--置本次存在標識為0,即存在
else
e := a;--結束日期=當前日期
if f = 0 then
b := a;--如果上次存在,則開始日期=當前日期
end if;
if a = '04-25' then--到4.25還沒有存在的日期就直接列印
p(b || ' ' || e);
end if;
f := 1;--置存在標識為1,即不存在
end if;
end loop;
end;
procedure showFoolEasterDay as
begin
p('YEAR TOTAL');
for i in 1 .. r.count loop
p(r(i) || ' ' || t);
end loop;
end;
begin
u.delete;
t := 0;
for i in f .. 2099 loop
d := i - f;
a := d mod 19;
c := (11 * a + 4 - trunc((7 * a + 1)/19)) mod 29;
b := 25-c-mod(d + trunc(d/4) + 31 - c, 7);
if b > 0
then a := '04'; c := b;
else a := '03'; c := 31+b;
end if;
c := lpad(c,2,0);
b := a||'-'||c;
v(d+1) := i || ' ' || b;
if b = '04-01' then t := t + 1; r(t) := i; end if;
if u.exists(b) then
e := u(b) + 1;--累計每個日期的出現次數
q := greatest(e,q);--取最大次數演算法
if b like '03%' then--取三月份最大次數演算法
m := greatest(e,m);
else--四月份最大次數演算法
n := greatest(e,n);
end if;
else e := 1;
end if;
u(b) := e;
end loop;
end;
/
最後,為了照顧到程式碼的完整性,可以將開始年份和結束年份變成以引數輸入。這個就不再貼出程式碼了,改動很簡單。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12932950/viewspace-693846/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 復活節最短原始碼比賽原始碼
- itpub 復活節最短sql(未完成程式碼)SQL
- 原始碼分析:Phaser 之更靈活的同步屏障原始碼
- 靈活且強大的RecyclerViewAdapter原始碼分析ViewAPT原始碼
- MapReduce —— MapTask階段原始碼分析(Input環節)APT原始碼
- MapReduce —— MapTask階段原始碼分析(Output環節)APT原始碼
- XP風格復活節彩蛋的實現 (轉)
- 微信活碼系統程式原始碼原始碼
- 復活
- C++Builder和Delphi中的復活節彩蛋 (轉)C++UI
- Retrofit原始碼分析三 原始碼分析原始碼
- Activiti 流程啟動及節點流轉原始碼分析原始碼
- 世界上最短的DVD解碼程式(附原始碼) (轉)原始碼
- 復活賽
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- Android 熱修復 Tinker 原始碼分析之DexDiff / DexPatchAndroid原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼
- 以太坊原始碼分析(38)event原始碼分析原始碼
- 以太坊原始碼分析(41)hashimoto原始碼分析原始碼
- 以太坊原始碼分析(43)node原始碼分析原始碼
- 以太坊原始碼分析(52)trie原始碼分析原始碼
- 《超級馬里奧大逃殺》被玩家復活 原始碼公開隨便玩原始碼
- 深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析MyBatis原始碼SQLSessionUI
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 【Android原始碼】Fragment 原始碼分析Android原始碼Fragment
- 【Android原始碼】Intent 原始碼分析Android原始碼Intent
- k8s client-go原始碼分析 informer原始碼分析(6)-Indexer原始碼分析K8SclientGo原始碼ORMIndex
- k8s client-go原始碼分析 informer原始碼分析(4)-DeltaFIFO原始碼分析K8SclientGo原始碼ORM
- 以太坊原始碼分析(20)core-bloombits原始碼分析原始碼OOM
- 以太坊原始碼分析(24)core-state原始碼分析原始碼
- 以太坊原始碼分析(29)core-vm原始碼分析原始碼
- 【MyBatis原始碼分析】select原始碼分析及小結MyBatis原始碼
- redis原始碼分析(二)、redis原始碼分析之sds字串Redis原始碼字串