하위 시퀀스가 ​​가장 많이 증가


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

자바 스크립트 (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}

이것은 특정 하위 시퀀스의 최대 값을 찾기 위해 펜윅 트리 (최대 펜윅 트리)를 사용합니다.

기본적으로 데이터 유형의 기본 배열에서 각 위치는 동일한 순서로 입력 목록의 요소와 일치합니다. 펜윅 트리는 어디에서나 0으로 초기화됩니다.

가장 작은 것에서 가장 큰 것까지 입력 목록에서 요소를 가져 와서 왼쪽에서 최대 요소를 찾습니다. 그것들은 입력 순서에서 왼쪽에 있기 때문에 하위 시퀀스에서이 요소 앞에있을 수있는 요소이며, 더 일찍 나무에 들어갔 기 때문에 더 작습니다.

우리가 찾은 최대 값은이 요소에 도달 할 수있는 가장 무거운 시퀀스이므로이 요소에 가중치를 더하고 트리에서 설정합니다.

그러면 전체 트리의 최대 값이 반환됩니다.

파이어 폭스에서 테스트


4

파이썬, O (n log 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))

런타임 분석 :

각 요소의 삽입 위치는 한 번 조회되고 한 번 삽입되며 루프 당 일정한 수의 값 조회 외에도 한 번 삭제 될 수 있습니다. 내장 bisect 패키지와 blist 패키지를 사용하고 있기 때문에 각각의 작업은 다음과 같습니다 O(log n). 따라서 전체 런타임은 O(n log n)입니다.

이 프로그램은 종료 값과 시퀀스 합계의 튜플로 표시되는 가능한 가장 높은 증가하는 서브 시퀀스의 정렬 된 목록을 유지함으로써 작동합니다. 종료 값이 더 작고 합이 최소한 큰 다른 서브 시퀀스가 ​​발견되지 않으면 서브 시퀀스가 ​​증가합니다. 이들은 끝 값의 증가 순서로, 그리고 또한 반드시 합의 순서로 유지됩니다. 이 특성은 새로 발견 된 각 서브 시퀀스의 후속 작업을 확인하고 해당 합계가 충분히 크지 않은 경우이를 삭제하고 더 큰 합계를 갖는 서브 시퀀스에 도달하거나 목록의 끝에 도달 할 때까지 반복하여 유지 보수합니다.


흥미롭고 것과는 매우 다른 솔루션 입니다 .
orlp

2

파이썬, O (n log 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

파이썬 O(n^2)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 ++를 사용하지 않는다는 것을 보여준다;)
Tyilo

훨씬 짧은 버전입니다 (여전히 세트와 벡터에 포함되어야 함).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

파이썬, 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.