Дана последовательность целых  чисел x[1],...,x[n].  Найти  максимальную длину ее возрастающей подпоследовательности (число действий порядка n*log(n)).

Решение. Искомая функция не индуктивна, но имеет  следующее индуктивное  расширение: в него входит помимо максимальной длины возрастающей подпоследовательности (обозначим ее k) также и числа u[1],...,u[k], где u[i] = (минимальный  из  последних  членов возрастающих  подпоследовательностей длины i). Очевидно, u[1]<=... <= u[k]. При добавлении нового члена x значения u и  k  корректируются.

  n1 := 1; k := 1; u[1] := x[1];
  {инвариант: k и u соответствуют данному выше описанию}
 
while n1 <> n do begin
 
| n1 := n1 + 1;
  | ...
  | {i - наибольшее из тех чисел отрезка 1..k, для кото-
  |   рых u[i] < x[n1]; если таких нет, то i=0 }
 
| if i = k then begin
  | | k := k + 1;
  | | u[k+1] := x[n1];
  | end else begin {i < k, u[i] < x[n1] <= u[i+1] }
  | | u[i+1] := x[n1];
  | end;
  end;

Фрагмент использует идею двоичного поиска; в инварианте условно полагаем u[0] равным минус бесконечности, а  u[k+1] - плюс бесконечности; наша цель: u[i] < x[n1] <= u[i+1].

 
i:=0; j:=k+1;
  {u[i] < x[n1] <= u[j], j > i}
  while (j - i) <> 1 do begin
  | s := i + (j-i) div 2;    {i < s < j}
  | if u[s] >= x[n1] then begin
  | | j := s;
  | end else begin {u[s] < x[n1]}
  | | i := s;
  | end;
  end;
  {u[i] < x[n1] <= u[j], j-i = 1}

Замечание.  Более  простое  (но не минимальное) индуктивное расширение получится, если для каждого  i  хранить  максимальную длину   возрастающей  подпоследовательности, оканчивающейся  на x[i]. Это расширение приводит к алгоритму с числом действий  по-
рядка n*n.


2009-12-04 • Просмотров [ 1413 ]