最长的算术和几何级数序列错误

时间:2012-11-27 21:18:10

标签: delphi delphi-7

我需要输入整数序列,找到最长的算术和几何级数。我写过这段代码(我必须使用Delphi 7)

program arithmeticAndGeometricProgression;
{ 203. In specifeied sequence of integer numbers find the longest sequence, which is
  arithmetic or geometric progression. }

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  sequence, longArithmSequ, longGeomSequ: Array of Integer;
  curArithmSequ, curGeomSequ: Array of Integer; // Current progress
  q, q1: Double;
  d1, d: Double;
  i, k: Integer;

begin
  i := 0;
  d := 0;
  k := 0;
  d1 := 0;

  Repeat
    SetLength(sequence, i + 1);
    // Make room for another item in the array
    try
      read(sequence[i]);
    except // If the input character is not an integer interrupt cycle
      Break;
    end;
    inc(i);
  Until False;

  k := 0;
  curArithmSequ := NIL;
  curGeomSequ := NIL;
  longArithmSequ := NIL;
  longGeomSequ := NIL;
  d1 := sequence[1] - sequence[0];
  q1 := sequence[1] / sequence[0];

  i := 1;

  repeat
    d := d1;
    q := q1;
    d1 := sequence[i] - sequence[i - 1];
    q1 := sequence[i] / sequence[i - 1];

    if d = d1 then
    begin
      SetLength(curArithmSequ, Length(curArithmSequ) + 1);
      curArithmSequ[Length(curArithmSequ) - 1] := sequence[i];
    end;

    if q = q1 then
    begin
      SetLength(curGeomSequ, Length(curGeomSequ) + 1);
      curGeomSequ[Length(curGeomSequ) - 1] := sequence[i];
    end;

    if Length(curArithmSequ) > Length(longArithmSequ) then
    begin
      longArithmSequ := NIL;
      SetLength(longArithmSequ, Length(curArithmSequ));
      for k := 0 to Length(curArithmSequ) - 1 do
        longArithmSequ[k] := curArithmSequ[k];
    end;

    if Length(curGeomSequ) > Length(longGeomSequ) then
    begin
      longGeomSequ := NIL;
      SetLength(longGeomSequ, Length(curGeomSequ));
      for k := 0 to Length(curGeomSequ) - 1 do
        longGeomSequ[k] := curGeomSequ[k];
    end;

    if d <> d1 then
      curArithmSequ := NIL;
    if q <> q1 then
      curGeomSequ := NIL;

    inc(i);
  Until i >= Length(sequence) - 1;

  writeLn('The Longest Arithmetic Progression');

  for k := 0 to Length(longArithmSequ) - 1 do
    Write(longArithmSequ[k], ' ');

  writeLn('The Longest Geometric Progression');
  for k := 0 to Length(longGeomSequ) - 1 do
    Write(longGeomSequ[k], ' ');
  Readln(k);

end.

我有这样的问题:

  1. 为什么它不能打印1-2个算术级数的成员
  2. 为什么它总是将'2'打印为几何级数
  3. 我的程序中是否有猴子式的代码?
  4. 请告诉我我的错误在哪里。

2 个答案:

答案 0 :(得分:4)

更新:

您需要以这种方式更改重复循环内的逻辑:

if d = d1 then
begin
  if (Length(curArithmSequ) = 0) then
  begin
    if (i > 1) then
      SetLength(curArithmSequ,3)
    else
      SetLength(curArithmSequ,2);
  end
  else
    SetLength(curArithmSequ,Length(curArithmSequ)+1);
  for k := 0 to Length(curArithmSequ) - 1 do
    curArithmSequ[k] := sequence[i - (Length(curArithmSequ) - k - 1)];
end
else
  SetLength(curArithmSequ,0);

if q = q1 then
begin
  if (Length(curGeomSequ) = 0) then
  begin
    if (i > 1) then
      SetLength(curGeomSequ,3)
    else
      SetLength(curGeomSequ,2);
  end
  else
    SetLength(curGeomSequ,Length(curGeomSequ)+1);
  for k := 0 to Length(curGeomSequ) - 1 do
    curGeomSequ[k] := sequence[i - (Length(curGeomSequ) - k - 1)];
end
else
  SetLength(curGeomSequ,0);

输入序列:

2,6,18,54 gives LAP=2,6 and LGP=2,6,18,54

输入序列为:

1,3,5,7,9 gives: LAP=1,3,5,7,9 and LGP=1,3

一系列

5,4,78,2,3,4,5,6,18,54,16 gives LAP=2,3,4,5,6 and LGP=6,18,54

这是我的完整测试(见下面的评论):

program arithmeticAndGeometricProgression;
{ 203. In specified sequence of integer numbers find the longest sequence, which is
  arithmetic or geometric progression. }

{$APPTYPE CONSOLE}

uses
  SysUtils;

Type
  TIntArr = array of integer;
  TValidationProc = function( const sequence : array of integer) : Boolean;

function IsValidArithmeticSequence( const sequence : array of integer) : Boolean;
begin
  Result :=
    (Length(sequence) = 2) // Always true for a sequence of 2 values
    or
    // An arithmetic sequence is defined by: a,a+n,a+2*n, ...
    // This gives: a+n - a = a+2*n - (a+n)
    // s[1] - s[0] = s[2] - s[1] <=> 2*s[1] = s[2] + s[0]
    (2*sequence[1] = (Sequence[2] + sequence[0]));
end;

function IsValidGeometricSequence( const sequence : array of integer) : Boolean;
var
  i,zeroCnt : Integer;
begin
  // If a zero exists in a sequence all members must be zero
  zeroCnt := 0;
  for i := 0 to High(sequence) do
    if (sequence[i] = 0) then
      Inc(zeroCnt);
  if (Length(sequence) = 2) then
    Result := (zeroCnt in [0,2])
  else
    // A geometric sequence is defined by: a*r^0,a*r^1,a*r^2 + ... ; r <> 0
    // By comparing sequence[i]*sequence[i-2] with Sqr(sequence[i-1])
    // i.e. a*(a*r^2) with Sqr(a*r) we can establish a valid geometric sequence
    Result := (zeroCnt in [0,3]) and (Sqr(sequence[1]) = sequence[0]*Sequence[2]);            
end;

procedure AddSequence( var arr : TIntArr; sequence : array of Integer);
var
  i,len : Integer;
begin
  len := Length(arr);
  SetLength(arr,len + Length(sequence));
  for i := 0 to High(sequence) do
    arr[len+i] := sequence[i];
end;

function GetLongestSequence( IsValidSequence : TValidationProc;
  const inputArr : array of integer) : TIntArr;
var
  i : Integer;
  currentSequence : TIntArr;
begin
  SetLength(Result,0);
  SetLength(currentSequence,0);
  if (Length(inputArr) <= 1)
    then Exit;
  for i := 1 to Length(inputArr)-1 do begin
    if (Length(Result) = 0) then // no valid sequence found so far
    begin
      if IsValidSequence([inputArr[i-1],inputArr[i]])
        then AddSequence(currentSequence,[inputArr[i-1],inputArr[i]]);
    end
    else
    begin
      if IsValidSequence([inputArr[i-2],inputArr[i-1],inputArr[i]]) then
      begin
        if (Length(currentSequence) = 0) then
          AddSequence(currentSequence,[inputArr[i-2],inputArr[i-1],inputArr[i]])
        else
          AddSequence(currentSequence,inputArr[i]);
      end
      else // Reset currentSequence
        SetLength(currentSequence,0);
    end;
    // Longer sequence ?
    if (Length(currentSequence) > Length(Result)) then
    begin
      SetLength(Result,0);
      AddSequence(Result,currentSequence);
    end;
  end;
end;

procedure OutputSequence( const arr : TIntArr);
var
  i : Integer;
begin
  for i := 0 to High(arr) do begin
    if i <> High(arr)
      then Write(arr[i],',')
      else WriteLn(arr[i]);
  end;
end;

begin
  WriteLn('Longest Arithmetic Sequence:');
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[0,1,2,3,4,5,6]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[1,0,1,2,3,4,5,6]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[0,0,0,0,0,0]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[0,0,1,2,4,8,16]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[0,0,6,9,12,4,8,16]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[9,12,16]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[1,0,1,-1,-3]));
  OutputSequence(GetLongestSequence(IsValidArithmeticSequence,[5,4,78,2,3,4,5,6,18,54,16]));

  WriteLn('Longest Geometric Sequence:');
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[0,1,2,3,4,5,6]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[1,0,1,2,3,4,5,6]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[0,0,0,0,0,0]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[0,0,1,2,4,8,16]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[0,0,6,9,12,4,8,16]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[9,12,16]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[1,0,9,-12,16]));
  OutputSequence(GetLongestSequence(IsValidGeometricSequence,[5,4,78,2,3,4,5,6,18,54,16]));
  ReadLn;
end.

正如大卫评论的那样,将浮点计算与整数混合会导致不必要的行为。例如。输入序列9,12,16的几何因子为4/3,这里可以使用,但其他类似的非整数几何因子可能会失败。需要进行更广泛的测试来验证这一点。


为了消除浮点运算的依赖性,可以在循环中进行以下更改:

// A geometric function is defined by a + n*a + n^2*a + ...
// By comparing sequence[i]*sequence[i-2] with Sqr(sequence[i-1])
// i.e. n^2*a*a with Sqr(n*a) we can establish a valid geometric sequence
q := Sqr(sequence[i-1]);
if (i < 2)
  then q1 := q // Special case, always true
  else q1 := sequence[i] * sequence[i - 2];

将d,d1,q,q1的声明更改为Integer并在循环之前删除q1的赋值。

更新测试代码以反映这些变化。


当序列具有一个或多个零用于几何序列计算时,存在问题。 如果所有值都为零,则零仅被视为几何序列的成员。

  

几何序列:a * r ^ 0,a * r ^ 1,a * r ^ 2等; r&lt;&gt; 0。   当a = 0时,进展仅由零组成。   这也意味着有效的几何序列不能同时包含非零值和零值。

用当前的结构纠正这个问题变得凌乱。所以我用更好的结构化程序更新了上面的测试,该程序处理所有输入序列。

答案 1 :(得分:4)

这是一个非常有趣的问题。 LU RD为您提供了修复代码的答案。作为替代方案,我提供了解决问题的方法:

program LongestSubsequence;

{$APPTYPE CONSOLE}

type
  TSubsequence = record
    Start: Integer;
    Length: Integer;
  end;

function Subsequence(Start, Length: Integer): TSubsequence;
begin
  Result.Start := Start;
  Result.Length := Length;
end;

type
  TTestSubsequenceRule = function(a, b, c: Integer): Boolean;

function FindLongestSubsequence(
  const seq: array of Integer;
  const TestSubsequenceRule: TTestSubsequenceRule
): TSubsequence;
var
  StartIndex, Index: Integer;
  CurrentSubsequence, LongestSubsequence: TSubsequence;
begin
  LongestSubsequence := Subsequence(-1, 0);
  for StartIndex := low(seq) to high(seq) do
  begin
    CurrentSubsequence := Subsequence(StartIndex, 0);
    for Index := CurrentSubsequence.Start to high(seq) do
    begin
      if (CurrentSubsequence.Length<2)
      or TestSubsequenceRule(seq[Index-2], seq[Index-1], seq[Index]) then
      begin
        inc(CurrentSubsequence.Length);
        if CurrentSubsequence.Length>LongestSubsequence.Length then
          LongestSubsequence := CurrentSubsequence;
      end
      else
        break;
    end;
  end;

  Result := LongestSubsequence;
end;

function TestArithmeticSubsequence(a, b, c: Integer): Boolean;
begin
  Result := (b-a)=(c-b);
end;

function FindLongestArithmeticSubsequence(const seq: array of Integer): TSubsequence;
begin
  Result := FindLongestSubsequence(seq, TestArithmeticSubsequence);
end;

function TestGeometricSubsequence(a, b, c: Integer): Boolean;
begin
  Result := (b*b)=(a*c);
end;

function FindLongestGeometricSubsequence(const seq: array of Integer): TSubsequence;
begin
  Result := FindLongestSubsequence(seq, TestGeometricSubsequence);
end;

procedure OutputSubsequence(const seq: array of Integer; const Subsequence: TSubsequence);
var
  Index: Integer;
begin
  for Index := 0 to Subsequence.Length-1 do
  begin
    Write(seq[Subsequence.Start + Index]);
    if Index<Subsequence.Length-1 then
      Write(',');
  end;
  Writeln;
end;

procedure OutputLongestArithmeticSubsequence(const seq: array of Integer);
begin
  OutputSubsequence(seq, FindLongestArithmeticSubsequence(seq));
end;

procedure OutputLongestGeometricSubsequence(const seq: array of Integer);
begin
  OutputSubsequence(seq, FindLongestGeometricSubsequence(seq));
end;

begin
  Writeln('Testing arithmetic sequences:');
  OutputLongestArithmeticSubsequence([]);
  OutputLongestArithmeticSubsequence([1]);
  OutputLongestArithmeticSubsequence([1,2]);
  OutputLongestArithmeticSubsequence([1,2,3]);
  OutputLongestArithmeticSubsequence([1,2,4]);
  OutputLongestArithmeticSubsequence([6,1,2,4,7]);
  OutputLongestArithmeticSubsequence([6,1,2,4,6,7]);

  Writeln('Testing geometric sequences:');
  OutputLongestGeometricSubsequence([]);
  OutputLongestGeometricSubsequence([1]);
  OutputLongestGeometricSubsequence([1,2]);
  OutputLongestGeometricSubsequence([1,2,4]);
  OutputLongestGeometricSubsequence([7,1,2,4,-12]);
  OutputLongestGeometricSubsequence([-16,-12,-9]);
  OutputLongestGeometricSubsequence([4,-16,-12,-9]);

  Readln;
end.

强调的关键是你的代码很难理解,因为所有不同的方面都是相互混合的。我在这里尝试将算法分解为更小的部分,可以单独理解。