從錯誤中學習
那天閒逛,發現了這個帖子,http://www.ituring.com.cn/Article/111574。
就用Delphi寫了一遍GetMaxAdjacentProdouct,寫完後發現執行速度還是很快的。
用GetTickCount用時總是0 ms,用精度更高的QueryPerformanceCounter則耗時0.60 ms;
比原帖的Haskell以及之前回復的Java、JavaScript都快。
題目中給出了連續數的個數為4時的正確答案,程式執行正確,便以為程式碼沒有錯誤。
回了原帖,並給出了連續數為13時的答案。然後洗洗睡了。
第二天再次看帖,卻發現樓主說答案錯誤,於是又仔細地看了看程式碼,的確發現一處bug。
為了提高效率,不用每次都重新計算連續12個數的乘積,
將第一次計算時的後12個數乘積結果保留下來作為nCommonProduct,
計算2-14的連續乘積時,便只需要nCommonProduct * 14th;
如何判斷是否第一次計算,為此引入了布林變數bIsFirst,初始賦值True,
每迴圈一次bIsFirst取反(bIsFirst := not bIsFirst)。
設連續數的個數為AdjacentNum,當前連續乘積的第一個數的索引為nIndex,
第1或者第AdjacentNum + 1個數的值賦值給nRemain,
則 nRemain := IfThen(bIsFirst, nIndex, nIndex + AdjacentNum)。
此處有一bug,bIsFirst取反後,已經迴圈了一次,即Index已經增加了1,
所以第二次的下標為nIndex + AdjacentNum - 1,
即 nRemain := IfThen(bIsFirst, nIndex, nIndex + AdjacentNum - 1)。
改完後自以為沒有問題了,又新增了回覆,並再次給出了AdjacentNum為[4,13]時的答案。
沒有想到的是,樓主再次告訴我“這題的正確答案仍然不是”。
不敢馬虎,再次仔細讀程式碼。可是的確沒有發現什麼錯誤。
一切回到起點,用最簡單的方法寫程式碼GetMaxAdjacentProdouct_Easy,
先得到正確答案,再優化效率,卻發現得到的答案還是和之前一樣……,
於是就在尤拉計劃的網站https://projecteuler.net/註冊了一個使用者,找到第8題,提交了答案,
依然顯示我提交的答案錯誤。看來,我的確是錯了。
再次仔細閱讀程式碼,依然沒有發現錯誤。
過了一段時間,想到是不是整型溢位了,於是將型別由Integer改為Int64,果然得到了一個新的答案。
再次在尤拉計劃的網站上提交,這次終於正確。
想起以前一位數學老師說過的話,再簡單的試卷,得滿分也是不容易的……
執行10000次,GetMaxAdjacentProdouct 耗時 620 ms左右,
GetMaxAdjacentProdouct_Easy 耗時 1380 ms左右,是前者的兩倍,和理論相符。
procedure EulerPlan_008;
var
nBegin, nEnd, nInterval, nFrequency, nProduct: Int64;
I: Integer;
oFile: TextFile;
sNumbers, sLine: string;
bIsSupport: Boolean;
arrNumbers: TByteDynArray;
begin
QueryPerformanceCounter(nBegin);
AssignFile(oFile, '..\..\008.txt');
Reset(oFile);
try
while not Eof(oFile) do
begin
Readln(oFile, sLine);
sNumbers := sNumbers + sLine;
end;
finally
CloseFile(oFile);
end;
//去掉空格及換行符號
sNumbers := StringReplace(sNumbers, ' ', '', [rfReplaceAll]);
sNumbers := StringReplace(sNumbers, #13#10, '', [rfReplaceAll]);
sNumbers := StringReplace(sNumbers, #13, '', [rfReplaceAll]);
Assert(Length(sNumbers) = 1000);
SetLength(arrNumbers, Length(sNumbers) + 1);
for I := 1 to High(arrNumbers) do
begin
arrNumbers[I] := StrToInt(sNumbers[I]);
end;
for I := 0 to 9999 do
begin
nProduct := GetMaxAdjacentProdouct_Easy(13, arrNumbers);
// nProduct := GetMaxAdjacentProdouct(13, arrNumbers);
end;
QueryPerformanceCounter(nEnd);
bIsSupport := QueryPerformanceFrequency(nFrequency);
nInterval := nEnd - nBegin;
nFrequency := IfThen(bIsSupport, nFrequency, 1);
ShowMessage(Format('乘積為 %d , 用時 %f ms.', [nProduct, (nInterval * 1000 / nFrequency)]));
end;
function GetMaxAdjacentProdouct(AdjacentNum: Integer;
ASrcNumbers: TByteDynArray): Int64;
var
nIndex, I: Integer;
bIsFirst: Boolean;
nRemain, nCommonProduct: Int64;
begin
Result := 0;
nIndex := 1;
bIsFirst := True;
nCommonProduct := -1;
while nIndex <= High(ASrcNumbers) - AdjacentNum + 1 do
begin
nRemain := IfThen(bIsFirst, ASrcNumbers[nIndex], ASrcNumbers[nIndex + AdjacentNum - 1]);
if nRemain = 0 then
begin
nIndex := IfThen(bIsFirst, nIndex + 1, nIndex + AdjacentNum);
bIsFirst := True;
Continue;
end;
if bIsFirst then
begin
nCommonProduct := 1;
for I := nIndex + 1 to nIndex + AdjacentNum - 1 do
begin
nCommonProduct := nCommonProduct * ASrcNumbers[I];
if nCommonProduct = 0 then
Break;
end;
end;
Result := Max(Result, nCommonProduct * nRemain);
Inc(nIndex);
bIsFirst := not bIsFirst;
end;
end;
function GetMaxAdjacentProdouct_Easy(AdjacentNum: Integer;
ASrcNumbers: TByteDynArray): Int64;
var
I, nIndex: Integer;
nProduct: Int64;
begin
Result := -1;
nIndex := 1;
while nIndex <= High(ASrcNumbers) - AdjacentNum + 1 do
begin
nProduct := 1;
for I := nIndex to nIndex + AdjacentNum - 1 do
begin
nProduct := nProduct * ASrcNumbers[I];
if nProduct = 0 then
Break;
end;
Inc(nIndex);
Result := Max(Result, nProduct);
end;
end;
相關文章
- 學習Rust 錯誤處理Rust
- QT 學習錯誤總結QT
- 《學習Oracle從這裡開始》之解決錯誤篇Oracle
- 《從零開始學Swift》學習筆記(Day54)——丟擲錯誤Swift筆記
- 在學習和使用rman過程中的坑和錯誤
- 《從零開始學Swift》學習筆記(Day 52)——Cocoa錯誤處理模式Swift筆記模式
- 學習Web前端需要避免哪些錯誤Web前端
- 今天學習遇見的錯誤!!!(禁忌)
- Python學習之錯誤除錯和測試Python除錯
- 從sysbench中學習Lua
- 我在學習程式設計中犯的兩個最大錯誤程式設計
- Golang 學習——error 錯誤處理淺談GolangError
- Golang 學習筆記八 錯誤異常Golang筆記
- 《從零開始學Swift》學習筆記(Day 53)——do-try-catch錯誤處理模式Swift筆記模式
- 物聯網學習教程—常見錯誤和程式除錯除錯
- JavaScript學習(2):物件、集合以及錯誤處理JavaScript物件
- 案例學習Oracle錯誤:TNS-00510(轉)Oracle
- 從錯誤中汲取經驗 - 我們在打造Buffer的過程中所學到的
- 從錯誤中汲取經驗 – 我們在打造Buffer的過程中所學到的
- mysql主從跳過錯誤MySql
- Ubuntu學習之apt-get update 升級錯誤Ubuntuapt-get
- Linux 學習錯誤點整理之網路配置Linux
- 案例學習Oracle錯誤:ORA-00922(轉)Oracle
- MySQL主從複製錯誤——列型別轉換錯誤MySql型別
- angular中ExpressionChangedAfterItHasBeenCheckedError錯誤AngularExpressError
- 從實踐中學習oracle/sql 1-3章學習OracleSQL
- 從bootstrap原始碼中學習Sass(一)boot原始碼
- 檢查 Linux 檔案系統中的錯誤:透過案例學習 FSCK 命令Linux
- 在 Istio 中除錯 503 錯誤除錯
- 從錯誤的RAID5中發現的問題AI
- 學習方法的錯誤:瞎想、粗看與蠻幹
- Python 3 學習筆記之——錯誤和異常Python筆記
- MySQL入門學習之——MySQL錯誤解決彙總MySql
- 案例學習Oracle錯誤:ORA-01631(轉)Oracle
- mysql 主從錯誤以及監控MySql
- android開發中犯的小錯誤,不要學我!Android
- 如何解決apache 403錯誤問題?Linux學習教程ApacheLinux
- Vben Admin 原始碼學習:狀態管理-錯誤日誌原始碼