Ответ 1
Просто добавьте их все и вычтите общее количество, которое вы ожидаете, если бы из него было использовано только 1001 номер.
Например:
Input: 1,2,3,2,4 => 12
Expected: 1,2,3,4 => 10
Input - Expected => 2
Недавно я столкнулся с вопросом:
Предположим, что у вас есть массив из 1001 целых чисел. Целые числа находятся в случайном порядке, но вы знаете, что каждое из целых чисел составляет от 1 до 1000 (включительно). Кроме того, каждый номер появляется только один раз в массиве, за исключением одного числа, которое встречается дважды. Предположим, что вы можете получить доступ к каждому элементу массива только один раз. Опишите алгоритм для поиска повторяющегося числа. Если вы использовали вспомогательное хранилище в своем алгоритме, можете ли вы найти алгоритм, который его не требует?
Мне интересно знать вторую часть, т.е. без использования вспомогательного хранилища. У вас есть идеи?
Просто добавьте их все и вычтите общее количество, которое вы ожидаете, если бы из него было использовано только 1001 номер.
Например:
Input: 1,2,3,2,4 => 12
Expected: 1,2,3,4 => 10
Input - Expected => 2
Обновление 2: Некоторые люди считают, что использование XOR для поиска дублирующего номера - это взломать или обмануть. На мой официальный ответ: "Я не ищу дублирующее число, я ищу дубликат шаблона в массиве битовых наборов. И XOR определенно подходит лучше, чем ADD для управления наборами бит".: -)
Обновление: Просто для удовольствия перед тем, как лечь спать, здесь однолинейное альтернативное решение, требующее нулевого дополнительного хранилища (даже не счетчика циклов), касается каждого элемента массива только один раз, неразрушающий и вообще не масштабируется: -)
printf("Answer : %d\n",
array[0] ^
array[1] ^
array[2] ^
// continue typing...
array[999] ^
array[1000] ^
1 ^
2 ^
// continue typing...
999^
1000
);
Обратите внимание, что компилятор фактически вычислит вторую половину этого выражения во время компиляции, поэтому "алгоритм" выполнит ровно 1002 операции.
И если значения элемента массива известны и во время компиляции, компилятор оптимизирует весь оператор до константы.: -)
Исходное решение:. Это не соответствует строгим требованиям, даже если оно работает, чтобы найти правильный ответ. Он использует одно дополнительное целое число, чтобы сохранить счетчик циклов, и он обращается к каждому элементу массива три раза - дважды, чтобы прочитать его и записать его на текущей итерации, и один раз прочитать его для следующей итерации.
Ну, вам нужна хотя бы одна дополнительная переменная (или регистр CPU) для хранения индекса текущего элемента при прохождении через массив.
Помимо этого, однако, здесь существует деструктивный алгоритм, который может безопасно масштабировать для любого N до MAX_INT.
for (int i = 1; i < 1001; i++)
{
array[i] = array[i] ^ array[i-1] ^ i;
}
printf("Answer : %d\n", array[1000]);
Я оставлю упражнение выяснить, почему это работает с вами, с простым намеком: -):
a ^ a = 0
0 ^ a = a
Неразрушающая версия решения Франци Пенова.
Это можно сделать, используя оператор XOR
.
Допустим, у нас есть массив размером 5
: 4, 3, 1, 2, 2
Которые находятся в индексе: 0, 1, 2, 3, 4
Теперь сделайте XOR
всех элементов и всех индексов. Мы получаем 2
, который является дублирующим элементом. Это происходит потому, что 0
не играет никакой роли в XORing. Остальные индексы n-1
объединяются с теми же элементами n-1
в массиве, и единственным непарным элементом в массиве будет дубликат.
int i;
int dupe = 0;
for(i = 0; i < N; i++) {
dupe = dupe ^ arr[i] ^ i;
}
// dupe has the duplicate.
Лучшей особенностью этого решения является то, что он не страдает от проблем с переполнением, что видно из решения, основанного на добавлении.
Поскольку это вопрос интервью, лучше всего начать с решения, основанного на добавлении, определить ограничение переполнения, а затем дать решение XOR
:)
Это использует дополнительную переменную, поэтому полностью не отвечает требованиям в вопросе.
Добавьте все числа вместе. Конечная сумма будет 1 + 2 +... + 1000 + дублирующимся числом.
Перефразируя решение Фрэнсиса Пенова.
Задача (обычная): задан массив целых чисел произвольной длины, содержащий только те элементы, которые повторяются четные моменты времени, за исключением одного значения, которое повторяется нечетным временем раз, узнайте это значение.
Решение:
acc = 0
for i in array: acc = acc ^ i
Ваша текущая проблема - это адаптация. Фокус в том, что вы должны найти элемент, который повторяется дважды, поэтому вам нужно адаптировать решение, чтобы компенсировать эту причуду.
acc = 0
for i in len(array): acc = acc ^ i ^ array[i]
Это то, что делает решение Фрэнсиса в конце, хотя оно уничтожает весь массив (кстати, он может уничтожить только первый или последний элемент...)
Но так как вам нужно дополнительное хранилище для индекса, я думаю, вам будет прощено, если вы также будете использовать дополнительное целое... Ограничение, скорее всего, связано с тем, что они хотят помешать вам использовать массив.
Это было бы сформулировано более точно, если бы потребовалось пространство O(1)
(1000 можно рассматривать как N, поскольку оно произвольно здесь).
Добавьте все номера. Сумма целых чисел 1..1000 равна (1000 * 1001)/2. Разница с тем, что вы получаете, это ваш номер.
Если вы знаете, что у нас есть точные цифры 1-1000, вы можете добавить результаты и вычесть 500500
(sum(1, 1000)
) из общей суммы. Это даст повторяющееся число, потому что sum(array) = sum(1, 1000) + repeated number
.
Ну, есть очень простой способ сделать это... каждый из чисел от 1 до 1000 происходит ровно один раз, за исключением числа, которое повторяется.... так что сумма от 1.... 1000 500500. Таким образом, алгоритм:
sum = 0 for each element of the array: sum += that element of the array number_that_occurred_twice = sum - 500500
arr = [1,3,2,4,2]
print reduce(lambda acc, (i, x): acc ^ i ^ x, enumerate(arr), 0)
# -> 2
Объяснение, почему оно работает, находится в @Matthieu M. answer.
Никаких дополнительных требований к хранению (кроме переменной цикла).
int length = (sizeof array) / (sizeof array[0]);
for(int i = 1; i < length; i++) {
array[0] += array[i];
}
printf(
"Answer : %d\n",
( array[0] - (length * (length + 1)) / 2 )
);
Допускаются ли аргументы и вызовы в качестве вспомогательного хранилища?
int sumRemaining(int* remaining, int count) {
if (!count) {
return 0;
}
return remaining[0] + sumRemaining(remaining + 1, count - 1);
}
printf("duplicate is %d", sumRemaining(array, 1001) - 500500);
Изменить: версия хвостового вызова
int sumRemaining(int* remaining, int count, int sumSoFar) {
if (!count) {
return sumSoFar;
}
return sumRemaining(remaining + 1, count - 1, sumSoFar + remaining[0]);
}
printf("duplicate is %d", sumRemaining(array, 1001, 0) - 500500);
n = 1000
s = sum(GivenList)
r = str(n/2)
duplicate = int( r + r ) - s
public static void main(String[] args) {
int start = 1;
int end = 10;
int arr[] = {1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 10};
System.out.println(findDuplicate(arr, start, end));
}
static int findDuplicate(int arr[], int start, int end) {
int sumAll = 0;
for(int i = start; i <= end; i++) {
sumAll += i;
}
System.out.println(sumAll);
int sumArrElem = 0;
for(int e : arr) {
sumArrElem += e;
}
System.out.println(sumArrElem);
return sumArrElem - sumAll;
}
public int duplicateNumber(int[] A) {
int count = 0;
for(int k = 0; k < A.Length; k++)
count += A[k];
return count - (A.Length * (A.Length - 1) >> 1);
}
Треугольное число T (n) - это сумма n натуральных чисел от 1 до n. Его можно представить в виде n (n + 1)/2. Таким образом, зная, что среди заданных 1001 натуральных чисел одно и только одно число дублируется, вы можете легко суммировать все заданные числа и вычесть T (1000). Результат будет содержать этот дубликат.
Для треугольного числа T (n), если n - любая степень 10, существует также прекрасный метод, нахо- дящий этот T (n), основанный на представлении базы 10:
n = 1000
s = sum(GivenList)
r = str(n/2)
duplicate = int( r + r ) - s
Улучшение ответа Fraci на основе свойства последовательных значений XORing:
int result = xor_sum(N);
for (i = 0; i < N+1; i++)
{
result = result ^ array[i];
}
Где:
// Compute (((1 xor 2) xor 3) .. xor value)
int xor_sum(int value)
{
int modulo = x % 4;
if (modulo == 0)
return value;
else if (modulo == 1)
return 1;
else if (modulo == 2)
return i + 1;
else
return 0;
}
Или в псевдокоде/математике f (n), определяемой как (оптимизированная):
if n mod 4 = 0 then X = n
if n mod 4 = 1 then X = 1
if n mod 4 = 2 then X = n+1
if n mod 4 = 3 then X = 0
И в канонической форме f (n) есть:
f(0) = 0
f(n) = f(n-1) xor n
Я поддерживаю добавление всех элементов, а затем вычитаю из него сумму всех индексов, но это не сработает, если количество элементов очень велико. То есть Это вызовет целочисленное переполнение! Поэтому я разработал этот алгоритм, который может значительно уменьшить вероятность переполнения целых чисел.
for i=0 to n-1
begin:
diff = a[i]-i;
dup = dup + diff;
end
// where dup is the duplicate element..
Но этим методом я не смогу узнать индекс, в котором присутствует повторяющийся элемент!
Для этого мне нужно пересечь массив еще раз, что нежелательно.
Мой ответ на вопрос 2:
Найдите сумму и произведение чисел от 1 - (до) N, скажем SUM
, PROD
.
Найдите сумму и произведение чисел из 1 - N- x -y, (предположим, что x, y отсутствует), скажем mySum, myProd,
Таким образом:
SUM = mySum + x + y;
PROD = myProd* x*y;
Таким образом:
x*y = PROD/myProd; x+y = SUM - mySum;
Мы можем найти x, y, если решить это уравнение.
В версии aux вы сначала устанавливаете все значения в -1, и когда вы повторяете проверку, если вы уже ввели это значение в массив aux. Если нет (значение должно быть -1), вставьте. Если у вас есть дубликат, вот ваше решение!
В случае без aux вы извлекаете элемент из списка и проверяете, содержит ли остальная часть списка это значение. Если он содержит, здесь вы его нашли.
private static int findDuplicated(int[] array) {
if (array == null || array.length < 2) {
System.out.println("invalid");
return -1;
}
int[] checker = new int[array.length];
Arrays.fill(checker, -1);
for (int i = 0; i < array.length; i++) {
int value = array[i];
int checked = checker[value];
if (checked == -1) {
checker[value] = value;
} else {
return value;
}
}
return -1;
}
private static int findDuplicatedWithoutAux(int[] array) {
if (array == null || array.length < 2) {
System.out.println("invalid");
return -1;
}
for (int i = 0; i < array.length; i++) {
int value = array[i];
for (int j = i + 1; j < array.length; j++) {
int toCompare = array[j];
if (value == toCompare) {
return array[i];
}
}
}
return -1;
}