Вот версия, которая тривиально O (sqrt (N)) и избегает всех внутренних контуров цикла.
Начните с генерации всех квадратов до предела, легко сделанных без каких-либо умножений, затем инициализируйте al иr index.
На каждой итерации вы вычисляете сумму, затем обновляете два индекса и счет на основе сравнения с целевым значением.Это sqrt (N) итераций для генерации таблицы и максимальные sqrt (N) итераций цикла поиска.Расчетное время работы с приемлемым компилятором составляет максимум 10 тактов на квадрат (N), поэтому для максимального входного значения, если 2 ^ 31 (sqrt (N) ~ = 46341), это должно соответствовать менее 500K тактов или нескольким десятымсекунды:
unsigned countPairs(unsigned n)
{
unsigned sq = 0, i;
unsigned square[65536];
for (i = 0; sq <= n; i++) {
square[i] = sq;
sq += i+i+1;
}
unsigned l = 0, r = i-1, count = 0;
do {
unsigned sum = square[l] + square[r];
l += sum <= n; // Increment l if the sum is <= N
count += sum == n; // Increment the count if a match
r -= sum >= n; // Decrement r if the sum is >= N
} while (l <= r);
return count;
}
Хороший компилятор может заметить, что все три сравнения в конце используют одни и те же операнды, поэтому ему нужен только один код операции CMP, за которым следуют три различные операции условного перемещения (CMOVcc).