Найважча зростаюча підпорядкованість


9

Послідовність - це послідовність, яка може бути отримана з іншої послідовності, видаливши деякі елементи, не змінюючи порядок решти елементів. Суворо зростаюча підпорядкованість - це послідовність, у якій кожен елемент більший за попередній.

Найбільш важкою послідовністю зростаючої послідовності є суттєво зростаюча послідовність, яка має найбільшу суму елементів.

Реалізуйте програму або функцію на обраній вами мові, яка знаходить суму елементів найбільш важкого зростаючого підпорядкування даного списку невід’ємних цілих чисел.

Приклади:

                    [] ->  0 ([])
                   [3] ->  3 ([3])
             [3, 2, 1] ->  3 ([3])
          [3, 2, 5, 6] -> 14 ([3, 5, 6])
       [9, 3, 2, 1, 4] ->  9 ([9])
       [3, 4, 1, 4, 1] ->  7 ([3, 4])
       [9, 1, 2, 3, 4] -> 10 ([1, 2, 3, 4])
       [1, 2, 4, 3, 4] -> 10 ([1, 2, 3, 4])
[9, 1, 2, 3, 4, 5, 10] -> 25 ([1, 2, 3, 4, 5, 10])
       [3, 2, 1, 2, 3] ->  6 ([1, 2, 3])

Зауважте, що ви повинні надати лише елементну суму найбільш важкої зростаючої послідовності, а не саму підпорядкованість.


Асимптотично найшвидший код виграє, з меншим розміром коду в байтах як перемикач.


Як ви плануєте боротися з незрівнянною асимптотикою? Можливо, є дві важливі змінні: довжина послідовності та розмір найбільшого елемента в послідовності.
Пітер Тейлор

@PeterTaylor Я обираю довжину послідовності як асимптотичну. Ваше рішення не повинно припускати жодних обмежень на цілі числа, і, зокрема, не циклічно чи розподіляти пам'ять, залежно від розміру залучених чисел. Вам прощають, якщо ваш вибір мови обмежив цілі числа, але ви не повинні використовувати цей факт у своєму рішенні. Чи задовольняє це ваше питання?
orlp

Частково. Теоретично все ще можливо (хоча ймовірно малоймовірно) той факт, що порівняння двох необмежених цілих чисел приймає розмір, пропорційний їхньому журналу, може бути актуальним. Ви можете дозволити базові операції (додавання, порівняння, можливо, множення) над цілими числами вважатись O (1) часом.
Пітер Тейлор

@PeterTaylor Чи достатньо специфічна трансдихотомна модель обчислень ?
orlp

Здається розумним.
Пітер Тейлор

Відповіді:


3

javascript (ES6) O(n log n)253 символи

function f(l){l=l.map((x,i)=>[x,i+1]).sort((a,b)=>a[0]-b[0]||1)
a=[0]
m=(x,y)=>x>a[y]?x:a[y]
for(t in l)a.push(0)
t|=0
for(j in l){for(i=(r=l[j])[1],x=0;i;i&=i-1)x=m(x,i)
x+=r[0]
for(i=r[1];i<t+2;i+=i&-i)a[i]=m(x,i)}for(i=t+1;i;i&=i-1)x=m(x,i)
return x}

для цього використовуються дерева фенвіку (максимум дерева фенвіку), щоб знайти максимуми певних підрядів.

в основному, в нижньому масиві типу даних кожне місце зіставляється з елементом зі списку введення в тому ж порядку. дерево fenwick ініціалізується з 0 всюди.

від найменшого до найбільшого, ми беремо елемент зі списку входів і шукаємо максимум елементів ліворуч. вони є елементами, які можуть бути перед цим у подальшому, тому що вони знаходяться ліворуч у послідовності введення, і менші, тому що вони раніше увійшли до дерева.

тому максимум, який ми знайшли, - це найважча послідовність, яка може дістатись до цього елемента, і тому ми додаємо до цього вагу цього елемента і встановлюємо його у дерево.

тоді ми просто повертаємо максимум всього дерева - це результат.

перевірена на firefox


4

Python, O (n журнал n)

Я не займався цим гольфом, тому що змагаюся в першу чергу за найшвидшим кодом. Моє рішення - це heaviest_subseqфункція, а також внизу є тестовий джгут.

import bisect
import blist

def heaviest_subseq(in_list):
    best_subseq = blist.blist([(0, 0)])
    for new_elem in in_list:

        insert_loc = bisect.bisect_left(best_subseq, (new_elem, 0))

        best_pred_subseq_val = best_subseq[insert_loc - 1][1]

        new_subseq_val = new_elem + best_pred_subseq_val

        list_len = len(best_subseq)
        num_deleted = 0

        while (num_deleted + insert_loc < list_len
               and best_subseq[insert_loc][1] <= new_subseq_val):
            del best_subseq[insert_loc]
            num_deleted += 1

        best_subseq.insert(insert_loc, (new_elem, new_subseq_val))

    return max(val for key, val in best_subseq)

tests = [eval(line) for line in """[]
[3]
[3, 2, 1]
[3, 2, 5, 6]
[9, 3, 2, 1, 4]
[3, 4, 1, 4, 1]
[9, 1, 2, 3, 4]
[1, 2, 4, 3, 4]
[9, 1, 2, 3, 4, 5, 10]
[3, 2, 1, 2, 3]""".split('\n')]

for test in tests:
    print(test, heaviest_subseq(test))

Аналіз виконання:

Кожен елемент має свою позицію вставки, звернуту один раз, вставляється один раз і, можливо, видаляється один раз, крім постійної кількості значень значень на цикл. Оскільки я використовую вбудований пакет бісектій та пакет blist , кожна з цих операцій є O(log n). Таким чином, загальний час виконання O(n log n).

Програма працює, підтримуючи відсортований список найкращих можливих зростаючих підпорядків, представлених у вигляді набору кінцевого значення та суми послідовностей. Зростаюча підпорядкованість знаходиться в цьому списку, якщо поки що не знайдено інших підрядностей, чиє кінцеве значення менше, а сума як мінімум така ж велика. Вони підтримуються у порядку збільшення значення закінчення, а також обов'язково в порядку збільшення суми. Це властивість зберігається шляхом перевірки наступника кожної щойно знайденої сукупності та видалення її, якщо її сума недостатньо велика, та повторення, поки не буде досягнуто підпорядкування з більшою сумою чи до кінця списку.


Цікаво, зовсім інше рішення від мого .
orlp

2

Python, O (n журнал n)

Я використовував перетворення індексу та чудову структуру даних (двійкове індексоване дерево), щоб реалізувати проблему.

def setmax(a, i, v):
    while i < len(a):
        a[i] = max(a[i], v)
        i |= i + 1

def getmax(a, i):
    r = 0
    while i > 0:
        r = max(r, a[i-1])
        i &= i - 1
    return r

def his(l):
    maxbit = [0] * len(l)
    rank = [0] * len(l)
    for i, j in enumerate(sorted(range(len(l)), key=lambda i: l[i])):
        rank[j] = i

    for i, x in enumerate(l):
        r = rank[i]
        s = getmax(maxbit, r)
        setmax(maxbit, r, x + s)

    return getmax(maxbit, len(l))

Двійкове індексоване дерево може виконати дві операції в log (n): збільшити значення в індексі i і отримати максимальне значення в [0, i). Ми ініціалізуємо кожне значення в дереві до 0. Ми індексуємо дерево, використовуючи ранг елементів, а не їх індекс. Це означає, що якщо ми індексуємо дерево за індексом i, всі елементи [0, i) є елементами меншими за той, що має ранг i. Це означає, що ми отримуємо максимум від [0, i), додаємо до нього поточне значення та оновлюємо його на i. Єдине питання полягає в тому, що це буде включати значення, які менші за поточне значення, але з’являються пізніше в послідовності. Але оскільки ми рухаємося через послідовність зліва направо і ми ініціалізуємо всі значення дерева у 0, вони матимуть значення 0 і, таким чином, не впливатимуть на максимум.


1

Python 2 - O(n^2)- 114 байт

def h(l):
 w=0;e=[]
 for i in l:
    s=0
    for j,b in e:
     if i>j:s=max(s,b)
    e.append((i,s+i));w=max(w,s+i)
 return w

1

C ++ - O(n log n)- 261 байт

Потрібно виправити зараз:

#include <set>
#include <vector>
int h(std::vector<int>l){int W=0,y;std::set<std::pair<int,int>>S{{-1,0}};for(w:l){auto a=S.lower_bound({w,-1}),b=a;y=prev(a)->second+w;for(;b!=S.end()&&b->second<=y;b++){}a!=b?S.erase(a,b):a;W=y>W?y:W;S.insert({w,y});}return W;}

auto S=set<pair<I,I>>();довше, ніж просто set<pair<I,I>> S;. #define I intдовше, ніж using I=int;. Там немає необхідності призначати nні до чого, ви можете замінити auto n=*prev(S.lower_bound({w,-1}));I y=n.secondз I y=prev(S.lower_bound({w,-1}))->second+w;.
orlp

О, і ініціалізація Sдуже суперечлива, ви можете просто відмовитися від вставки та використовувати std::set<std::pair<int,int>>S{{-1,0}};.
orlp

@orlp спасибі! Звідси видно, що я не використовую c ++;)
Тайло

Ось набагато коротша версія (все ще потрібен набір і вектор включити):using namespace std;using I=int;I h(vector<I>l){I W=0;set<pair<I,I>>S{{-1,0}};for(I w:l){I y=prev(S.lower_bound({w,-1}))->second+w;W=max(W,y);S.insert({w,y});}return W;}
orlp

Ой і скидайте std::max, використовуйте W=y>W?y:W;.
orlp

0

Matlab, O ( n 2 n ), 90 байт

function m=f(x)
m=0;for k=dec2bin(1:2^numel(x)-1)'==49
m=max(m,all(diff(x(k))>0)*x*k);end

Приклади:

>> f([])
ans =
     0
>> f([3])
ans =
     3
>> f([3, 2, 5, 6])
ans =
    14

0

Python, O (2 n ), 91 байт

Це більше для розваги, ніж для конкуренції. Таємне рекурсивне рішення:

h=lambda l,m=0:l and(h(l[1:],m)if l[0]<=m else max(h(l[1:],m),l[0]+h(l[1:],l[0])))or 0

1
max(m,l[0])враховуючи, що not(l[0]<m)це просто l[0], точно?
Пітер Тейлор

@PeterTaylor Derp.
orlp

Ця відповідь не є серйозним претендентом.
pppery
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.