방법 요소의 최대 집합을 찾는


14

알고리즘 문제가 있습니다.

음이 아닌 n 개의 정수로 구성된 배열 (또는 집합) T 가 주어 집니다. 최대 세트 찾기 ST를 같은 그 모든 S , | S | .nSTaSa|S|

예를 들면 다음과 같습니다.

  1. 만약에T = [1, 3, 4, 1, 3, 6],S 될 수있다 (3, 3), (6)] 또는 [3, 4, 6] 또는 [4, 3,6].
  2. 에서는 T = [7, 5, 1, 1, 7, 4] 다음 S 이다 [7, 5, 7, 4].

이 재귀 함수를 시도했습니다.

function(T):
    if minimum(T) >= length(T): 
        return T
    else: 
        return function(T\minimum(T))

비 재귀 알고리즘이 있습니까? (재귀 알고리즘을 확인하지 않았으므로 결함이있을 수 있습니다.)

답변:


14

T를 정렬 한 다음 동안 요소를 가져옵니다 T[i] >= i+1.

예를 들면 sorted(T)=[6,4,3,3,1,1]. 그런 다음 T[0] = 6 > 1, T[1] = 4 > 2, T[2] = 3 <= 3그리고 마지막으로, T[3] = 3 < 4우리는있다 S = [T[0], T[1], T[2]].


3
이것은 물론, 다른 솔루션 그리워 ,하지만 영업 이익은 찾고 있었다 나타납니다 어떤 것이 아니라, 솔루션 모든 솔루션을 제공합니다. {6,,}
Rick Decker

2
올바른 요소 수를 얻습니다. 우리는 3 가지 요소를 가진 솔루션을 가지고 있지만 4 가지를 가진 솔루션은 없다는 것을 알고 있습니다. 이 경우 4 개 이상의 요소가 3 개이므로 솔루션에 대해 3 개를 선택할 수 있습니다.
gnasher729

3
정확성에 대한 논쟁에 감사드립니다.
Raphael

아마도 introselect의 변형으로 O (n) 시간 안에 할 수 있다고 생각합니다.
user2357112는

8

내 댓글 출신이 밀접하게 학문적 생산성 평가에서 수량 유비쿼터스 관련되면, Hirsh 지수는 더 잘 알려진 -indexh . 간단히 말해서 이는 출판물의 수로서 정의된다 하나는 그들 각각 적어도 갖도록 보유 시간 서지 (최대 같은 시간 동안 ).hhh

당신의 문제가 다른 유일한 방법은 당신이 얼마나 많은 출판물이 기준을 만족시키는 지뿐만 아니라 그들의 인용 횟수가 무엇인지에 관심이 있다는 것입니다 . 그러나 그것은 사소한 수정입니다. 데이터가 이미 있으며 원래 알고리즘은 삭제합니다.

일반적으로 구현 된 계산 은 다소 간단하며 Karolis Juodelė의 답변에 동의합니다 .

업데이트 : 데이터의 크기와 특성에 따라 피봇 포인트 위와 아래에서 데이터를 필터링하여 배열을 부분적으로 정렬하는 방법을 탐색하는 것이 좋습니다 (quicksort가 떠 오릅니다). 그런 다음 너무 적거나 너무 많은지 여부에 따라 피벗을 포함하는 하위 집합에서 피벗 및 다시 실행을 조정합니다. 보다 높은 요소 사이에는 순서가 필요하지 않으며 확실히 그보다 낮은 요소 사이에는 필요하지 않습니다 . 예를 들어, 모든 요소가 h 1 보다 크거나 같은 것을 발견 하고 그 중 h 1 보다 작은 것이 발견되면 해당 하위 세트를 다시 만질 필요가 없습니다. 이는 퀵 정렬에 고유 한 재귀를 테일 재귀 로 변환 하므로 루프로 다시 쓸 수 있습니다.hh1h1

내 Haskell은 약간 녹슬지 만 위의 내용을 따라야 작동합니다. 어느 정도 이해할 수 있기를 바랍니다. 추가 설명을 드리겠습니다.

-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys

-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
  | x == (1 + lGreater + lGranted) = x : merge greater granted
  | x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
  | otherwise = topImpl greater granted
  where smaller = [y | y <- xs, y < x]
        greater = [y | y <- xs, y >= x]
        lGreater = length greater
        lGranted = length granted

-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []

아이디어는 granted결과에 확실히 참여할 것으로 알고 있는 것을 수집하고 더 이상 정렬하지 않는 것입니다. fit greater과 함께 사용 하면 x운이 좋으며 그렇지 않은 경우 더 작은 하위 집합으로 시도해야합니다. (피벗은 x현재 간주 하위 목록의 첫 번째 항목 우연히 어떤 간단하다.) 참고 하나 가장 큰 요소 중 하나를 복용에 대한 중요한 장점은 우리가 평균 크기의 블록에이 작업을 수행한다는 것을 더 정렬 할 필요가 없습니다.remaining/2

예:

당신의 세트를 보자 [1,3,4,1,3,6].

  1. x = 1, granted = [], greater = [3,4,1,3,6]. 우리 smaller는 첫 번째 단계에서 피벗이 너무 작을 때 (실제로는 너무 작음) 병리학 적 사례를 맞았습니다 . 운 좋게도 우리 알고는 그 준비가되어 있습니다. 혼자 버리고 x다시 시도합니다 greater.

  2. x = 3, granted = [], greater = [4,3,6]. 함께, 그들은 길이 4의 배열을 형성하지만 우리는 아래에서 3으로 제한하기 때문에 너무 많습니다. greater혼자 반복하십시오 .

  3. x = 4, granted = [], greater = [6]. 이것은 각각 ≥ 4의 2 요소 배열을 제공합니다. 이것을 유지하고에 반복하십시오 smaller = [3].

  4. x = 3, granted = [4,6], greater = []. 이것은 함께 3 개 이상의 요소 3 개로 구성된 배열을 제공하므로 우리는 해 [3,4,6]를 구할 수 있습니다. 순열은 입력 순서에 따라 다를 수 있지만 항상 [3,3,6]또는 가능한 한 가장 높은 항을 포함합니다 [3,3,4].

(Btw. 재귀는 실제로 사이클로 축소되었습니다.) 복잡성이 저장된 비교가 많기 때문에 퀵 정렬보다 다소 낫습니다.

n1

O(logn)O(n)

nO(n2)

위의 코드에는 불필요하게 비교할 smaller수 있습니다. 필요한지 여부를 계산 하는 것과 같이 쉽게 제거 할 수 있습니다. (나는 게으른 평가가 그것을 처리 할 것이라고 생각합니다.)


6

알고리즘에는 아무런 문제가 없으며 물론 대부분의 재귀 알고리즘은 루프로 변환 될 수 있습니다. 여기에서는 재귀 코드의 루프 버전입니다.

function(T):
    while minimum(T) <= lenght(T):
         remove minimum(T) from T
    loop

6
모든 재귀 알고리즘을 루프로 변환 할 수 있습니다. 결국 튜링 머신은 재귀에 대해 아무것도 모릅니다.
David Richerby

4

반복을 사용하기 위해 모든 재귀 알고리즘을 다시 작성할 수 있습니다. 결국 튜링 머신은 재귀에 대해 아무것도 모르지만 알고리즘을 구현할 수 있습니다. 원칙적으로 자체 스택 조작 코드를 작성하여 함수 매개 변수의 값과 로컬 변수를 기억함으로써 재귀 함수를 다시 작성할 수 있습니다. 이 특별한 경우, 함수는 꼬리 재귀 (재귀 호출이 반환되면 즉시 호출 한 것이 반환 됨)이므로 스택을 유지할 필요조차 없습니다.


3

전체 배열을 정렬 할 필요가 없으므로 min-heap을 사용하여 부분 힙 정렬을 수행하십시오.

주어진 임계 값을 초과 할 때까지 요소를 탐욕스럽게 유지하십시오.


2
또한 정확성에 대한 아이디어에 감사드립니다.
Raphael
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.