那天闲逛,发现了这个帖子,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;