Це питання інтерв'ю, яке я декілька разів переживав, і я не впевнений, як його вирішити, враховуючи, що чотири числа відсутні. Мені знайомі алгоритми пошуку одного чи двох чисел відсутні, але я не бачу способу узагальнити жодне з них до чотирьох.
Це питання інтерв'ю, яке я декілька разів переживав, і я не впевнений, як його вирішити, враховуючи, що чотири числа відсутні. Мені знайомі алгоритми пошуку одного чи двох чисел відсутні, але я не бачу способу узагальнити жодне з них до чотирьох.
Відповіді:
Незалежно від того, що стосується співбесіди чи фактичної роботи, вашим першим пріоритетом має бути робоче рішення, яке має для вас сенс . Це зазвичай означає , що ви повинні запропонувати перше рішення , яке ви можете думати , що це просто і легко для вас , щоб пояснити.
Для мене це означає сортувати числа та сканувати прогалини. Але я працюю над бізнес-системами та веб-додатками. Я не воюю з бітами, і я не хочу, щоб моя команда!
Якщо ви берете співбесіду для роботи на низькому рівні, ближчій до металу, "сортування", ймовірно, зустрінеться з порожніми поглядами. Вони хочуть, щоб вам було зручно думати про шматочки тощо. Ваша перша відповідь там повинна бути: "О, я б використав растрову карту". (Або бітовий масив, або встановлений біт.)
І тоді, в будь-якому випадку - навіть якщо ви даєте "неправильне" рішення, якщо ваш інтерв'юер (або начальник!) Натискає на нього , ви можете запропонувати деякі вдосконалення чи альтернативи, зосередившись на певній проблемі менеджера.
O(n*log(n)). (Або O (n) для цілого ряду відра!)BitSet/ BitMap/ BitArray)BitArrayщоб позначити "знайдені числа". А потім скануйте на 0's.BitArray/BitSet(щоб знайти0імена). ОцеO(n), я думаю!Або що завгодно.
Вирішіть проблеми, які ви насправді маєте. Просто вирішіть проблему спочатку, використовуючи наївні рішення, якщо необхідно. Не витрачайте часу на вирішення проблем, які ще не існують.
Оскільки це файл, я припускаю, що вам дозволяється робити кілька проходів. Спочатку створіть масив з 256 лічильників, повторіть файл і для кожного числа збільште лічильник, індексований як перший байт числа. Коли ви закінчите, більшість лічильників мають бути 2 ^ 24, але 1 до 4 лічильників повинні мати нижчі значення. Кожен з цих індексів являє собою перший байт одного з пропущених чисел (якщо їх менше 4, це тому, що кілька пропущених чисел мають один і той же перший байт).
Для кожного з цих індексів створіть інший масив з 256 лічильників та зробіть другий прохід у файлі. Цього разу, якщо перший байт є одним із значень раніше, збільшуйте лічильник у своєму масиві на основі другого байта. Коли ви закінчите, подивіться ще раз лічильники нижче 2 ^ 16, і ви отримаєте другий байт пропущених чисел, кожен з яких відповідає першому байту.
Зробіть це ще раз для третього байта (зауважте, що вам потрібно максимум 4 масиви в кожному проході, хоча за кожним байтом може бути до 4 різних байтів) і для четвертого байту, і ви знайшли всі пропущені числа.
Часова складність - Складність O(n * log n)
простору - постійна !
Власне, я вважав цей n=2^32параметр, але кількість відсутніх чисел k=4також є параметром. Якщо припустити, k<<nце означає, що складність простору є O(k).
Просто для розваги (а тому, що я зараз намагаюся вивчити іржу) я реалізував це в Rust: https://gist.github.com/idanarye/90a925ebb2ea57de18f03f570f70ea1f . Я вибрав текстове представлення, оскільки він буде запускати його з ~ 2 ^ 32 числами ...
Якби це Java, ви можете використовувати BitSet. Ну, два з них, тому що вони не можуть цілком утримувати всі 32 бітні числа. Скелетний код, можливо, баггі:
BitSet bitsetForPositives = new Bitset(2^31); // obviously not 2^31 but you get the idea
BitSet bitsetForNegatives = new Bitset(2^31);
for (int value: valuesTheyPassInSomehow) {
if ((value & 0x80000000) == 0)
bitsetForPositives.set(value );
else
bitsetForNegatives.set(value & ~0x80000000);
}
Потім використовуйте BitSet.nextClearBit()для пошуку того, хто відсутній.
Примітка додана набагато пізніше:
Зауважте, що за допомогою цього алгоритму паралельно запускати частину, що забирає час, досить легко . Скажімо, початковий файл розділено на чотири приблизно рівні частини. Виділіть 4 пари BitSets (2 Гб, все ще керовані).
Я б очікував, що введення-виведення все ще буде кроком, що обмежує швидкість, але якби магічно всі цифри були в пам'яті, ви могли б дійсно прискорити роботу.
Integer.MIN_VALUEправильно. Ви можете замаскувати біт знака замість того, щоб заперечувати його.
bool GetBit(byte[] byteArray, uint index) { var byteIndex = index >> 3; var bitInByte = index & 7; return (byteArray[byteIndex] >> bitInByte) & 1 != 0; }
Це питання можна вирішити за допомогою масиву бітів (true / false). Це має бути найбільш ефективною структурою, щоб вмістити відповіді на всі числа, використовуючи індекс масиву, щоб утримувати, чи було знайдено саме це число.
C #
var bArray = new BitArray(Int32.MaxValue);
//Assume the file has 1 number per line
using (StreamReader sr = File.OpenText(fileName))
{
string s = String.Empty;
while ((s = sr.ReadLine()) != null)
{
var n = int32.Parse(s);
bArray[n] = true;
}
}
Потім просто повторіть масив і для тих значень, які все ще є помилковими, їх немає у файлі.
Ви можете розбити файл на менші шматки, але мені вдалося виділити повний масив максимального розміру int32 (2147483647) на моєму ноутбуці потужністю 16,0 ГБ під управлінням Windows 7 (64 біт).
Навіть якби я не працював на 64 біті, я міг би виділити менші бітові масиви. Я би попередньо обробив файл, створивши набір менших файлів, кожен з діапазоном номерів [0-64000] [64001-128000] тощо, який би був відповідним для наявних екологічних ресурсів. Пройдіть великий файл і запишіть кожне число у відповідний набір файлів. Потім обробіть кожен менший файл. Через крок попередньої обробки це займе трохи більше часу, але це дозволить обійти обмеження ресурсів, якби ресурси були обмежені.
Оскільки це питання інтерв'ю, я б показав інтерв'юеру деяке розуміння обмежень. Тоді, що означає "всі можливі числа"? Це дійсно 0 ... 2 <(32-1), як усі здогадуються? Звичайні 32-бітні архітектури можуть працювати з багатьма більш ніж 32-бітовими числами. Очевидно, це лише питання представництва.
Це має бути вирішено в 32-бітній системі, чи це, скоріше, частина обмеження чисел? Наприклад, типова 32-бітна система не зможе завантажити файл відразу в ОЗУ. Я також зазначу, що 32-бітна система часто не зможе мати файл, що містить усі числа через обмеження розміру файлу. Ну, якщо тільки воно не має розумного кодування, як-от "Усі числа, крім цих чотирьох", і в цьому випадку проблема вирішується тривіально.
Але якщо ви дійсно хочете зрозуміти питання як "З огляду на файл із усіма числами від 0 ... 2 ^ (32-1), крім кількох, дайте мені відсутні" (і це великий, якщо !), То Є багато способів вирішити це.
Тривіальне, але нездійсненне. Для кожного можливого числа скануйте файл і перевірте, чи він там є.
За допомогою 512 Мб оперативної пам’яті та одного проходу через файл: позначте кожне число (= встановлений біт у цьому індексі), прочитане з файлу, а потім передайте оперативну пам’ять один раз і побачите пропущені.
Один із підходів, який легко запам’ятати і легко сформулювати в інтерв’ю, - це використовувати той факт, що якщо переглянути всі числа в N бітах, кожен біт буде встановлений у рівно половині цих значень, а не встановлений в іншій половині .
Якщо ви повторите всі значення у файлі і збережете 32 підрахунки значень у кінці, ви отримаєте 32 значення, які точно (2 ^ 32/2) або трохи менше цього значення. Різниця, що максимальна (2 ^ 32/2) і загальна, дає вам загальний біт, встановлений у кожному положенні пропущених значень.
Після цього ви зможете визначити всі можливі набори з 4 значень, які могли б дати ці підсумки. Враховуючи це, ви можете знову пройти значення у файлі, перевіривши, чи немає значень, що входять до складу цих комбінацій. Коли ви знайдете його, комбінації, що містять це значення, усуваються як можливості. Як тільки у вас залишилася лише одна можлива комбінація, ви отримаєте відповідь.
Наприклад, використовуючи nibble, у вас є такі значення:
1010
0110
1111
0111
1101
1001
0100
0101
0001
1011
1100
1110
Загальна кількість бітів, встановлених у кожній позиції, становить:
7867
Віднімаючи ті з 8 (4 ^ 2/2), отримуємо:
1021
Що означає наступні можливі набори з 4 значень:
1000
0000
0011
0010
1010
0001
0010
0000
(пробачте мене, якщо я пропустив будь-яке, я це роблю лише з виду)
А потім знову переглядаючи оригінальні цифри, ми знаходимо 1010, тобто перший набір був відповіддю.
determine all the possible sets of 4 values that could give those totals. Я дійсно думаю, що це важлива частина рішення, якого немає у вашій відповіді. Це також може вплинути на часову та просторову складність.
Якщо припустити, що файл сортується за збільшенням чисел:
Переконайтесь, що воно індексує містить (2³-4) цифри.
Тепер, якщо файл був повним (або якщо 4 відсутні числа були останніми 4), читання будь-якого слова у файлі в положенні N поверне відповідне значення N.
Використовуйте дихотомічний пошук по позиціях [0..2³²-4-1) для пошуку першого не очікуваного числа X1.
Виявивши це перше пропущене число, зробіть повторно диктотомію по позиціях [X1 .. (2³²-4-1)], щоб знайти друге відсутнє, X2: На цей раз, читаючи слово у позиції N, слід повернути відповідне значення N-1 якщо не було більше відсутніх номерів (оскільки ви передали один пропущений номер).
Ітерайте аналогічно для двох залишилися чисел. На третій ітерації слово читання в положенні N повинно повертати N-2, а на четвертій - N-3.
Caveat: Я цього не перевіряв. Але я думаю, що це має спрацювати. :)
Зараз у реальному житті я погоджуюся з іншими відповідями: перші питання стосувалися б навколишнього середовища. Чи є у нас оперативна пам'ять (скільки), чи є файл на пристрої зберігання прямого доступу, це операція з одним знімком (не потрібна оптимізація) чи критична (кожен цикл), чи є у нас зовнішня утиліта сортування і т. д.
Потім знайдіть компроміс, прийнятний для контексту. Принаймні, це показує, що ви починаєте аналізувати проблему, перш ніж шукати алгоритм.
Як і у всіх стандартних питаннях, вирішення полягає в тому, щоб погукати їх перед інтерв'ю.
На це запитання та варіанти є дуже певна «правильна» відповідь, що включає XORing всіх чисел. Це повинно показувати, що ви розумієте індекси в базах даних чи щось. Таким чином, нульові бали за будь-який "може спрацювати, але не те, що написано на папері", відповідь негайно.
З іншого боку, існує обмежений набір цих запитань. Через декілька годин перегляд зробить вас схожим на генія. Просто не забудьте зробити вигляд, що ви це працюєте в голові.
Редагувати. Ага, здається, для 4 існує інший підхід, ніж XOR
Редагувати. Далі: Це рішення опублікованого підручника O (n) точної проблеми, зазначеної в ОП.