我有以下问题:
如果我们列出10以下的所有自然数,它们是3或3的倍数 5,我们得到3,5,6和9.这些倍数的总和是23。
查找低于1000的3或5的所有倍数的总和。
这是我用来尝试解决问题的代码(Edit1是输出,Edit2是问题引发的数字):
procedure TForm1.Button1Click(Sender: TObject);
var i, answer : longint;
begin
answer := 0;
for i := 0 to strtoint(Edit2.text) - 1 do begin
if i mod 3 = 0 then answer := answer + i;
if i mod 5 = 0 then answer := answer + i;
end;
Edit1.Text := inttostr(answer);
end;
输入数字10到Edit2(编辑框)将输出:23,如问题所示。在Edit2中输入数字13将输出35,这也是正确的
由于某种原因,当将输入提高到1000时,输出为:266333;当作为答案输入时,被认为是不正确的。
编辑:我已将代码更改为重复计算,这是更新版本:
procedure TForm1.Button1Click(Sender: TObject);
var i, answer : longint;
begin
answer := 0;
for i := 0 to strtoint(Edit2.text) - 1 do begin
if i mod 3 = 0 then answer := answer + i;
if i mod 5 = 0 then begin
if not i mod 3 = 0 then begin
answer := answer + i;
end;
end;
end;
Edit1.Text := inttostr(answer);
end;
这仍未给出正确答案。
答案 0 :(得分:3)
你重复计算。任何数字都是3和5的倍数将被计算两次。还有什么可以从1开始循环而不是零。您可以像这样修复代码:
answer := 0;
for i := 1 to strtoint(Edit2.text) - 1 do begin
if (i mod 3 = 0) or (i mod 5 = 0) then
answer := answer + i;
end;
但是,如果将代码与用户界面分开,则代码更容易理解。你也可以把它变得更加通用。所以,你的代码可能如下所示:
function SumOfMultiples(const N: Integer;
const Candidates: array of Integer): Integer;
var
i, j: Integer;
begin
Result := 0;
for i := 1 to N-1 do
for j := 0 to high(Candidates) do
if i mod Candidates[j] = 0 then
begin
inc(Result, i);
break;
end;
end;
这里的关键是使用break
。一旦我们发现一个数字是一个数字,我们增加运行总数,并打破内部循环。这避免了重复计算。
要找到3和5的倍数之和,小于10,你会写:
SumOfMultiples(10, [3, 5])
我确信可以优化代码以避免任何循环。您需要执行以下操作:
实施很简单,至少对候选人而言:
function SumOfMultiples(const N, k: Integer): Integer; overload;
var
Count: Integer;
begin
Assert(N>0);
Assert(k>0);
Count := (N-1) div k;
Result := k*Count*(Count+1) div 2;
end;
function SumOfMultiples(const N, k1, k2: Integer): Integer; overload;
begin
Assert(k1<>k2);
Result := SumOfMultiples(N, k1) + SumOfMultiples(N, k2)
- SumOfMultiples(N, k1*k2);
end;
我想对两个以上的候选人来说会有点棘手。无论如何,这不是问题,但它可能会成为一个非常有趣的项目,以备不时之需!