Чи існують алгоритми O (1 / n)?
Або що-небудь інше, що менше O (1)?
Чи існують алгоритми O (1 / n)?
Або що-небудь інше, що менше O (1)?
Відповіді:
Це питання не настільки дурне, як може здатися. Принаймні теоретично щось таке, як O (1 / n ), є цілком розумним, коли ми беремо математичне визначення нотації Big O :
Тепер ви можете легко замінити g ( x ) на 1 / x ... очевидно, що вищевказане визначення все ще має місце для деякого f .
Для того, щоб оцінити зростання асимптотичного періоду виконання, це є менш життєздатним… осмислений алгоритм не може отримати швидше, оскільки вхід зростає. Звичайно, ви можете побудувати довільний алгоритм для цього, наприклад наступний:
def get_faster(list):
how_long = (1 / len(list)) * 100000
sleep(how_long)
Зрозуміло, що ця функція витрачає менше часу, оскільки розмір вводу збільшується ... принаймні, поки не встановиться деякий ліміт, який забезпечується апаратним забезпеченням (точність чисел, мінімум часу, який sleep
може чекати, час на обробку аргументів тощо): цей обмеження буде тоді константа нижньої межі, тому фактично зазначена функція все ще має час виконання O (1).
Але це насправді реальних алгоритмів , де Виконавча може зменшуватися (принаймні , частково) , коли збільшується розмір вхідного. Зауважте, що ці алгоритми не демонструватимуть поведінки під час виконання ( O) (1). Все-таки вони цікаві. Наприклад, візьміть дуже простий алгоритм пошуку тексту Horspool . Тут очікувана тривалість виконання зменшиться зі збільшенням тривалості шаблону пошуку (але збільшення довжини стога сіна знову збільшить час виконання).
Так.
Існує точно один алгоритм з режимом виконання O (1 / n), "порожній" алгоритм.
Якщо алгоритм є O (1 / n), це означає, що він виконує асимптотично за менші кроки, ніж алгоритм, що складається з однієї інструкції. Якщо він виконується менш, ніж один крок для всіх n> n0, він не повинен точно складатися з інструкцій для цих n. Оскільки перевірка "якщо n> n0" коштує щонайменше 1 інструкція, вона не повинна містити інструкцій для всіх n.
Підведення підсумків: Єдиним алгоритмом, який є O (1 / n), є порожній алгоритм, що не складається з інструкцій.
shartooth є правильним, O (1) - найкраща можлива ефективність. Однак це не означає швидке рішення, а лише фіксований час.
Цікавим варіантом, і можливо, що насправді пропонується, є те, які проблеми стають легшими в міру зростання населення. Я можу придумати 1, хоч і надуману відповідь:
У кого-небудь двоє людей в наборі один і той же день народження? Коли n перевищує 365, поверніть true. Хоча для менш ніж 365, це O (n ln n). Можливо, це не чудова відповідь, оскільки проблема не стає повільніше, а просто стає O (1) для n> 365.
Це неможливо. Визначення Big-O є не більше ніж нерівність:
A(n) = O(B(n))
<=>
exists constants C and n0, C > 0, n0 > 0 such that
for all n > n0, A(n) <= C * B(n)
Таким чином, B (n) насправді є максимальним значенням, тому, якщо воно зменшується в міру збільшення n, оцінка не зміниться.
З мого попереднього вивчення великої нотації O, навіть якщо вам потрібен 1 крок (наприклад, перевірка змінної, виконання завдання), тобто O (1).
Зауважте, що O (1) - це те саме, що O (6), оскільки "константа" не має значення. Тому ми кажемо, що O (n) - це те саме, що O (3n).
Отже, якщо вам потрібен навіть 1 крок, це O (1) ... а оскільки вашій програмі потрібно щонайменше 1 крок, мінімальним алгоритмом може бути O (1). Якщо ми цього не зробимо, я думаю, це О (0)? Якщо ми взагалі щось робимо, то це O (1), і це мінімум, який він може досягти.
(Якщо ми вирішимо не робити цього, то це може стати питанням дзен або дао ... у царині програмування O (1) все ще є мінімумом).
А як щодо цього:
програміст : бос, я знайшов спосіб це зробити в O (1) час!
бос : не потрібно цього робити, ми сьогодні вранці збанкрутуємо.
програміст : о, тоді він стає O (0).
Ні, це неможливо:
Оскільки n має тенденцію до нескінченності в 1 / n, ми в кінцевому підсумку досягаємо 1 / (inf), що ефективно дорівнює 0.
Таким чином, великим класом задачі буде O (0) з масивним n, але ближчим до постійного часу з низьким n. Це нерозумно, оскільки єдине, що можна зробити швидше, ніж постійний час, це:
void nothing() {};
І навіть це сперечається!
Як тільки ви виконуєте команду, ви принаймні O (1), так що ні, ми не можемо мати клас великого-O (1 / n)!
А як щодо взагалі не запустити функцію (NOOP)? або за допомогою фіксованого значення. Це враховує?
Я часто використовую O (1 / n), щоб описати ймовірності, які зменшуються, коли входи збільшуються - наприклад, ймовірність того, що справедлива монета з’являється хвостиками на перекидах log2 (n), є O (1 / n).
O (1) просто означає "постійний час".
Додаючи ранній вихід до циклу [1], ви (у великій нотації O) перетворюєте алгоритм O (1) на O (n), але робите його швидшим.
Трюк, як правило, алгоритм постійного часу найкращий, а лінійний - краще, ніж експоненціальний, але для малих кількостей n алгоритм експоненції може бути фактично швидшим.
1: Припустимо статичну довжину списку для цього прикладу
Для тих, хто читає це питання і хоче зрозуміти, про що йдеться, це може допомогти:
| |constant |logarithmic |linear| N-log-N |quadratic| cubic | exponential |
| n | O(1) | O(log n) | O(n) |O(n log n)| O(n^2) | O(n^3) | O(2^n) |
| 1 | 1 | 1 | 1| 1| 1| 1 | 2 |
| 2 | 1 | 1 | 2| 2| 4| 8 | 4 |
| 4 | 1 | 2 | 4| 8| 16| 64 | 16 |
| 8 | 1 | 3 | 8| 24| 64| 512 | 256 |
| 16 | 1 | 4 | 16| 64| 256| 4,096 | 65536 |
| 32 | 1 | 5 | 32| 160| 1,024| 32,768 | 4,294,967,296 |
| 64 | 1 | 6 | 64| 384| 4,069| 262,144 | 1.8 x 10^19 |
Я вважаю, що квантові алгоритми можуть робити кілька обчислень "відразу" за допомогою суперпозиції ...
Сумніваюсь, це корисна відповідь.
багато людей мали правильну відповідь (Ні) Ось ще один спосіб довести це: Щоб мати функцію, вам потрібно викликати функцію, і ви повинні повернути відповідь. Це займає певну постійну кількість часу. НАДІЛЬКО, якщо на іншу обробку знадобиться менше часу для більшого введення, друк відповіді (що ми можемо вважати одним бітом) займає щонайменше постійний час.
Якщо рішення існує, його можна підготувати та отримати доступ до нього в постійний час = негайно. Наприклад, використовуючи структуру даних LIFO, якщо ви знаєте, що запит сортування призначений у зворотному порядку. Потім дані вже сортуються, враховуючи, що обрана відповідна модель (LIFO).
Які проблеми стають легшими у міру зростання населення? Одна відповідь - така річ, як bittorrent, де швидкість завантаження - це зворотна функція кількості вузлів. На відміну від автомобіля, який сповільнює, чим більше ви завантажуєте його, мережа для обміну файлами, як битторент, прискорює більше підключених вузлів.
Ви не можете піти нижче O (1), проте O (k) там, де k менше, ніж N. Ми називали їх підлінійними алгоритмами часу . У деяких проблемах алгоритм підлінійного часу може дати лише приблизні рішення певної проблеми. Однак іноді приблизні рішення є просто чудовими, ймовірно, тому, що набір даних занадто великий, або що це занадто обчислювально дорого для обчислення всіх.
Як що до цього:
void FindRandomInList(list l)
{
while(1)
{
int rand = Random.next();
if (l.contains(rand))
return;
}
}
зі збільшенням розміру списку очікувана тривалість виконання програми зменшується.
constains
O (1)
O (1 / n) не менше O (1), це в основному означає, що чим більше у вас даних, тим швидше йде алгоритм. Скажімо, ви отримуєте масив і завжди заповнюєте його до 10 100 елементів, якщо в ньому менше, ніж нічого, і нічого не робити, якщо є більше. Це, звичайно, не O (1 / n), але щось на зразок O (-n) :) Занадто поганий O-великий позначення не дозволяє негативних значень.
Як було зазначено, окрім можливого виключення нульової функції, функцій не може бути O(1/n)
, оскільки час, який потрібно, повинен наблизитися до 0.
Звичайно, є деякі алгоритми, такі, як визначений Конрадом, які, здається, мають бути меншими, ніж O(1)
хоча б у якомусь сенсі.
def get_faster(list):
how_long = 1/len(list)
sleep(how_long)
Якщо ви хочете дослідити ці алгоритми, вам слід визначити власне асимптотичне вимірювання, або власне уявлення про час. Наприклад, у вищенаведеному алгоритмі я міг дозволити використання декількох "вільних" операцій у встановлену кількість разів. У наведеному вище алгоритмі, якщо я визначаю t ', виключаючи час на все, крім сну, то t' = 1 / n, що є O (1 / n). Напевно, є кращі приклади, оскільки асимптотична поведінка тривіальна. Насправді я впевнений, що хтось там може придумати відчуття, які дають нетривіальні результати.
Більшість решти відповідей інтерпретують big-O виключно щодо часу виконання алгоритму. Але оскільки питання не згадувало про це, я вважав, що варто згадати інше застосування big-O в числовому аналізі, що стосується помилки.
Багато алгоритмів можуть бути O (h ^ p) або O (n ^ {- p}), залежно від того, йдеться про розмір кроку (h) або кількість поділів (n). Наприклад, у методі Ейлера ви шукаєте оцінку y (h), враховуючи, що ви знаєте y (0) і dy / dx (похідна від y). Ваша оцінка y (h) точніша, тим ближче h до 0. Отже, щоб знайти y (x) для деякого довільного x, потрібно взяти інтервал від 0 до x, розбити його до n частин і запустити метод Ейлера в кожній точці дістати від y (0) до y (x / n) до y (2x / n) тощо.
Тож метод Ейлера - це алгоритм O (h) або O (1 / n), де h, як правило, інтерпретується як розмір кроку, а n інтерпретується як кількість раз ділення інтервалу.
Ви також можете мати O (1 / год) у реальних програмах чисельного аналізу через помилки округлення з плаваючою комою . Чим менше ви робите свій інтервал, тим більше відбувається скасування впровадження певних алгоритмів, тим більше втрата значущих цифр, а отже, і більше помилок, які поширюються через алгоритм.
Для методу Ейлера, якщо ви використовуєте плаваючі точки, використовуйте досить невеликий крок і скасування, і ви додаєте невелике число до великого числа, залишаючи велике число незмінним. Для алгоритмів, які обчислюють похідну шляхом віднімання один від одного двох чисел з функції, оціненої у двох дуже близьких положеннях, наближаючи y '(x) до (y (x + h) - y (x) / h), в гладких функціях y (x + h) наближається до y (x), що призводить до великої відміни та оцінки похідної з меншою кількістю значущих цифр. Це, в свою чергу, пошириться на той алгоритм, для якого вам потрібна похідна (наприклад, проблема граничного значення).
Гаразд, я трохи подумав над цим, і, можливо, існує алгоритм, який би міг відповідати цій загальній формі:
Вам потрібно обчислити проблему продавця подорожі для графіка 1000 вузлів, однак, вам також надається список вузлів, які ви не можете відвідати. Із збільшенням списку невидимих вузлів проблема стає легшою для вирішення.
Я бачу алгоритм, який O (1 / n) належить до верхньої межі:
У вас є велика серія входів, які змінюються через щось, що не відповідає рутинному (можливо, вони відображають обладнання або це може бути навіть якесь інше ядро в процесорі, що це робить.), І ви повинні вибрати випадковий, але дійсний.
Тепер, якщо це не змінилося, ви просто складете список предметів, виберіть один випадковим чином і отримаєте O (1) час. Однак динамічний характер даних перешкоджає складанню списку, вам просто доведеться досліджувати випадковим чином і перевірити дійсність зонду. (І зауважте, що за своєю суттю немає гарантії, що відповідь все ще діє, коли вона повернеться. Це все-таки може мати користь - скажімо, AI для підрозділу в грі. Це може стріляти в ціль, яка випала з поля зору, поки вона була потягнувши курок.)
Це має найгірший показник нескінченності, але середній показник ефективності, який зменшується у міру заповнення простору даних.
У числовому аналізі алгоритми апроксимації повинні мати субстантную асимптотичну складність у допущенні наближення.
class Function
{
public double[] ApproximateSolution(double tolerance)
{
// if this isn't sub-constant on the parameter, it's rather useless
}
}
Я думаю, що менше O (1) неможливо. Будь-який час, взятий альго, називається O (1). Але для O (1 / n) як щодо функції нижче. (Я знаю, що в цьому рішенні вже представлено багато варіантів, але, мабуть, всі вони мають деякі недоліки (не основні, вони добре пояснюють концепцію). Ось ось один, лише заради аргументу:
def 1_by_n(n, C = 10): #n could be float. C could be any positive number
if n <= 0.0: #If input is actually 0, infinite loop.
while True:
sleep(1) #or pass
return #This line is not needed and is unreachable
delta = 0.0001
itr = delta
while delta < C/n:
itr += delta
Таким чином, у міру збільшення n функція займе все менше часу. Також гарантується, що якщо вхід фактично дорівнює 0, то функція буде повертатися назавжди.
Можна стверджувати, що це буде обмежено точністю машини. таким чином, sinc eit має верхню межу - це O (1). Але ми можемо обійти це також, взявши введення n та C в рядку. І додавання та порівняння робиться на рядок. Ідея полягає в тому, що за допомогою цього ми можемо скоротити n довільно малих. Таким чином, верхня межа функції не обмежена, навіть якщо ми ігноруємо n = 0.
Я також вважаю, що ми не можемо просто сказати, що час виконання - O (1 / n). Але ми повинні сказати щось на зразок O (1 + 1 / n)
Можливо, можливо побудувати алгоритм, який є O (1 / n). Одним із прикладів може бути цикл, який повторює деякий кратний f (n) -n разів, коли f (n) - деяка функція, значення якої гарантовано перевищує n, а межа f (n) -n, коли n наближається до нескінченності, нуль. Розрахунок f (n) також повинен бути постійним для всіх n. Я не знаю з іншого боку, як виглядатиме f (n) або яким би було застосування такого алгоритму, на мою думку, однак така функція могла б існувати, але отриманий алгоритм не мав би іншого призначення, як довести можливість алгоритму з O (1 / n).
Я не знаю про алгоритми, але складності менше O (1) з'являються у рандомізованих алгоритмах. Власне, o (1) (мало o) менше O (1). Така складність зазвичай з'являється в рандомізованих алгоритмах. Наприклад, як ви сказали, коли ймовірність якоїсь події є порядку 1 / n, вони позначають її о (1). Або коли вони хочуть сказати, що щось відбувається з великою часткою ймовірності (наприклад, 1 - 1 / n), вони позначають це з 1 - o (1).
Якщо відповідь однакова незалежно від вхідних даних, то у вас є алгоритм O (0).
або іншими словами - відповідь відома до подачі вхідних даних - функція може бути оптимізована - так O (0)
Позначення Big-O являє собою найгірший сценарій для алгоритму, який не є тим самим, що його типовий час виконання. Довести, що алгоритм O (1 / n) є алгоритмом O (1), просто. За визначенням,
O (1 / n) -> T (n) <= 1 / n, для всіх n> = C> 0
O (1 / n) -> T (n) <= 1 / C, оскільки 1 / n <= 1 / C для всіх n> = C
O (1 / n) -> O (1), оскільки нотація Big-O ігнорує константи (тобто значення C не має значення)
hashtable-contains
алгоритму, який можна позначити як O (1) - і найгірший випадок може бути заданий дуже точно як Theta (n)! Омега та Тета можуть просто використовуватися для позначення інших меж, але сказати це знову : вони не мають нічого спільного із середнім чи кращим випадком.
Ніщо не менше, ніж O (1) Позначення Big-O передбачає найбільший порядок складності алгоритму
Якщо алгоритм має час виконання n ^ 3 + n ^ 2 + n + 5, то це O (n ^ 3) Нижні сили тут взагалі не мають значення, оскільки як n -> Inf, n ^ 2 буде неактуальним порівняно з п ^ 3
Так само, як n -> Inf, O (1 / n) буде неактуальним порівняно з O (1), отже, 3 + O (1 / n) буде таким же, як O (1), завдяки чому O (1) є найменшим можливим обчислювальним складність
inline void O0Algorithm() {}
Ось простий алгоритм O (1 / n). І це навіть робить щось цікаве!
function foo(list input) {
int m;
double output;
m = (1/ input.size) * max_value;
output = 0;
for (int i = 0; i < m; i++)
output+= random(0,1);
return output;
}
O (1 / n) можливий, оскільки він описує, як змінюється вихід функції з урахуванням збільшення розміру вводу. Якщо ми використовуємо функцію 1 / n для опису кількості вказівок, яку виконує функція, то немає необхідності, щоб функція приймала нульові інструкції для будь-якого розміру вводу. Швидше, це те, що для кожного розміру вводу, n над деяким порогом, кількість необхідних інструкцій обмежена вище на позитивну константу, помножену на 1 / n. Оскільки немає фактичного числа, для якого 1 / n дорівнює 0, а константа позитивна, то немає жодної причини, чому функція обмежувалася б приймати 0 чи менше інструкцій.