Ответ 1
Теоретически
В O (1) пространстве (в модели ОЗУ, то есть O (1)) возможно и O (n) время даже с массивом только для чтения.
Предупреждение: длинный пост с некоторой математикой. Если вас интересует только код, а не алгоритм/доказательство, перейдите к разделу кода. Однако вам нужно прочитать некоторые части алгоритма, чтобы понять код.
Алгоритм
Предположим, что недостающие числа - это x и y.
Для массива существует две возможности:
1) Одно число повторяется три раза, а остальные числа в массиве появляются ровно один раз.
Для этого случая будет выполняться трюк XOR с квадратом.
Сделайте XOR всех элементов массива с 1,2,..., n.
В итоге вы получите z = x XOR y.
Существует по крайней мере один бит z, который отличен от нуля.
Теперь, дифференцируя элементы массива на основе этого бита (два ведра), снова пропустите XOR через массив.
В итоге вы получите x и y.
Как только у вас есть x и y, вы можете подтвердить, действительно ли это недостающие элементы.
Если так получится, что шаг подтверждения не удался, тогда мы должны иметь второй случай:
2) Два элемента повторяются ровно дважды, а остальные появляются ровно один раз.
Пусть два повторяющихся элемента - a и b (x и y - недостающие).
Предупреждение: математика впереди.
Пусть S_k = 1^k + 2^k + .. + n^k
Например S_1 = n(n+1)/2
, S_2 = n(n+1)(2n+1)/6
и т.д.
Теперь мы вычислим семь вещей:
T_1 = Sum of the elements of the array = S_1 + a + b - x - y.
T_2 = Sum of the squares = S_2 + a^2 + b^2 - x^2 - y^2
T_3 = Sum of cubes = S_3 + a^3 + b^3 - x^3 - y^3
T_4 = Sum of fourth powers = S_4 + a^4 + b^4 - x^4 - y^4
...
T_7 = Sum of seventh powers = S_7 + a^7 + b^7 - x^7 - y^7
Примечание. Мы можем использовать слова O (1) (intsead of one) для решения проблем с переполнением. (Я считаю, 8-10 слов будет достаточно).
Пусть Ci = T_i - S_i
Предположим теперь, что a, b, x, y являются корнями полинома 4-й степени P(z) = z^4 + pz^3 + qz^2 + rz + s
Теперь мы попытаемся преобразовать указанные семь уравнений в четыре линейных уравнения в p,q,r,s
.
Например, если мы делаем 4th Eqn + p * 3rd Eqn + q* 2nd equation + r* 1st equation
получаем
C4 + p*C3 + q*C2 + r*C1 = 0
Аналогично получаем
C5 + p*C4 + q*C3 + r*C2 + s*C1 = 0
C6 + p*C5 + q*C4 + r*C3 + s*C2 = 0
C7 + p*C6 + q*C5 + r*C4 + s*C3 = 0
Это четыре линейных уравнения в p,q,r,s
, которые могут быть решены методами линейной алгебры, такими как гауссово исключение.
Обратите внимание, что p,q,r,s
будет рациональным и поэтому может быть вычислен только с целочисленной арифметикой.
Теперь предположим, что мы получили решение p,q,r,s
к приведенной выше системе уравнений.
Рассмотрим P(z) = z^4 + pz^3 + qz^2 + rz + s
.
То, что говорят вышеприведенные уравнения, в основном
P(a) + P(b) - P(x) - P(y) = 0
aP(a) + bP(b) - xP(x) -yP(y) = 0
a^2 P(a) + b^2 P(b) - x^2 P(x) - y^2 P(y) = 0
a^3 P(a) + b^3 P(b) - x^3 P(x) - y^3 P(y) = 0
Теперь матрица
1 1 -1 -1
a b -x -y
a^2 b^2 -x^2 -y^2
a^3 b^3 -x^3 -y^3
имеет тот же детерминант, что и матрица Вандермонда и поэтому обратим, если a,b,x,y
различны.
Таким образом, мы должны иметь P(a) = P(b) = P(x) = P(y) = 0
.
Теперь проверьте, какие из 1,2,3,...,n
являются корнями x^4 + px^3 + qx^2 + rx + s = 0
.
Таким образом, это линейный алгоритм пространственного пространства времени.
код
Я написал следующий код С# (.Net 4.0) и, похоже, работает для нескольких образцов, которые я пробовал... (Примечание: я не беспокоился о том, чтобы обслуживать случай 1 выше).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;
namespace SOManaged
{
class Program
{
static void Main(string[] args)
{
ulong[] inp = {1,3,2,1,2};
ulong[] inp1 = { 1,2,3,4,5,6,7,8,
9,10,11,13,14,15,
16,17,18,19,20,21,5,14};
int N = 100000;
ulong[] inp2 = new ulong[N];
for (ulong i = 0; i < (ulong)N; i++)
{
inp2[i] = i+1;
}
inp2[122] = 44;
inp2[419] = 13;
FindMissingAndRepeated(inp);
FindMissingAndRepeated(inp1);
FindMissingAndRepeated(inp2);
}
static void FindMissingAndRepeated(ulong [] nums)
{
BigInteger[] C = new BigInteger[8];
// Compute the C_i
for (int k = 0; k < 8; k++)
{
C[k] = 0;
}
BigInteger i = 1;
BigInteger n = 0;
for (int j = 0; j < nums.Length; j++)
{
n = nums[j];
i = j + 1;
for (int k = 1; k < 8; k++)
{
C[k] += i - n;
n = n * nums[j];
i = i * (j + 1);
}
}
for (int k = 1; k <= 7; k++)
{
Console.Write("C[" + k.ToString() + "] = " +
C[k].ToString() +", ");
}
Console.WriteLine();
// Solve for p,q,r,s
BigInteger[] pqrs = new BigInteger[4];
BigInteger[] constants = new BigInteger[4];
BigInteger[,] matrix = new BigInteger[4, 4];
int start = 4;
for (int row = 0; row < 4; row++ )
{
constants[row] = -C[start];
int k = start-1;
for (int col = 0; col < 4; col++)
{
matrix[row, col] = C[k];
k--;
}
start++;
}
Solve(pqrs, matrix, constants, 4);
for (int k = 0; k < 4; k++)
{
Console.Write("pqrs[" + k.ToString() + "] = "
+ pqrs[k].ToString() + ", ");
}
Console.WriteLine();
// Find the roots.
for (int k = 1; k <= nums.Length; k++)
{
BigInteger x = new BigInteger(k);
BigInteger p_k = x * x * x* x + pqrs[0] * x* x * x
+ pqrs[1] * x * x + pqrs[2] * x
+ pqrs[3];
if (p_k == 0)
{
Console.WriteLine("Found: " + k.ToString());
}
}
}
// Solve using Cramer method.
// matrix * pqrs = constants.
static void Solve(BigInteger[] pqrs, BigInteger[,] matrix,
BigInteger[] constants, int n)
{
BigInteger determinant = Determinant(matrix, n);
for (int i = 0; i < n; i++)
{
BigInteger[,] numerator = Replace(matrix, constants, n, i);
BigInteger numDet = Determinant(numerator,4);
pqrs[i] = numDet/ determinant;
}
}
// Replace a column of matrix with constants.
static BigInteger[,] Replace(BigInteger[,] matrix,
BigInteger[] constants, int n, int col)
{
BigInteger[,] newMatrix = new BigInteger[n, n];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (j != col)
{
newMatrix[i, j] = matrix[i, j];
}
else
{
newMatrix[i, j] = constants[i];
}
}
}
return newMatrix;
}
// Recursively compute determinant for matrix.
static BigInteger Determinant(BigInteger[,] matrix, int n)
{
BigInteger determinant = new BigInteger(0);
int multiplier = 1;
if (n == 1)
{
return matrix[0,0];
}
for (int i = 0; i < n; i++)
{
BigInteger [,] subMatrix = new BigInteger[n-1,n-1];
int row = 0;
for (int j=1; j < n; j++)
{
int col = 0;
for (int k = 0; k < n ; k++)
{
if (k == i)
{
continue;
}
subMatrix[row,col] = matrix[j,k];
col++;
}
row++;
}
BigInteger subDeterminant = Determinant(subMatrix, n - 1);
determinant += multiplier * subDeterminant * matrix[0,i];
multiplier = -multiplier;
}
return determinant;
}
}
}
Выходной сигнал
C[1] = 6, C[2] = 36, C[3] = 180, C[4] = 864, C[5] = 4116, C[6] = 19656, C[7] = 9
4380,
pqrs[0] = -12, pqrs[1] = 49, pqrs[2] = -78, pqrs[3] = 40,
Found: 1
Found: 2
Found: 4
Found: 5
C[1] = 15, C[2] = 407, C[3] = 9507, C[4] = 215951, C[5] = 4861515, C[6] = 108820
727, C[7] = 2424698067,
pqrs[0] = -53, pqrs[1] = 980, pqrs[2] = -7396, pqrs[3] = 18480,
Found: 5
Found: 12
Found: 14
Found: 22
C[1] = 486, C[2] = 189424, C[3] = 75861486, C[4] = 31342069984, C[5] = 130971109
69326, C[6] = 5492487308851024, C[7] = 2305818940736419566,
pqrs[0] = -600, pqrs[1] = 83183, pqrs[2] = -3255216, pqrs[3] = 29549520,
Found: 13
Found: 44
Found: 123
Found: 420