Это можно перевести в решение с постоянным временем, используя немного математики. Короче говоря, мы просто находим Ожидаемое значение .
TL; DR
sum(1:n) * (n + 1) / 2
, равное:
(n * (n + 1) / 2) * (n + 1) / 2 -->> n * (n + 1)^2 / 4
constantTimeMean <- function(n) n * (n + 1)^2 / 4
constantTimeMean(5)
[1] 45
Пояснение
Пусть (x 1 , x 2 , ... x n ) - перестановка чисел 1 до n . Умножьте каждый x i на i и сложите примерно так:
x_1 * 1 + x_2 * 2 ... + x_n * n
Поскольку мы берем все перестановки, каждый индекс i имеет равную вероятность быть умноженным на каждое число от 1 до n . Также отметим, что если мы удалим коэффициенты, сумма каждой перестановки будет постоянной (то есть sum(1:n)
). Таким образом, все, что нам нужно сделать, это вычислить среднее значение от 1 до n и умножить на сумму от 1 до n .
Закрытое выражение в виде суммы от 1 до n определяется как:
(n * (n + 1) / 2)
Вместе со средним значением получаем :
n * (n + 1)^2 / 4
Это хорошо, потому что генерация всех перестановок выходит из-под контроля очень быстро. Например, что если мы установим N = 15 или даже N = 4321 ? Это facrorial(15) = 1.307674e+12
перестановок ... генерация уже невозможна (factorial(4321)
возвращает Inf
... Используя пакет gmp
, мы видим, что он действительно имеет более 13000 десятичных цифр: gmp::log10.bigz(gmp::factorialZ(4321)) ~= 13834.99
). Тем не менее, с формулой выше, это не проблема:
system.time(print(constantTimeMean(15)))
[1] 960
user system elapsed
0 0 0
system.time(print(constantTimeMean(4321)))
[1] 20178728641
user system elapsed
0 0 0