https://app.codility.com/programmers/lessons/10-prime_and_composite_numbers/flags/start/
A non-empty array A consisting of N integers is given.
A peak is an array element which is larger than its neighbours. More precisely, it is an index P such that 0 < P < N − 1 and A[P − 1] < A[P] > A[P + 1].
For example, the following array A:
A[0] = 1
A[1] = 5
A[2] = 3
A[3] = 4
A[4] = 3
A[5] = 4
A[6] = 1
A[7] = 2
A[8] = 3
A[9] = 4
A[10] = 6
A[11] = 2
has exactly four peaks: elements 1, 3, 5 and 10.
You are going on a trip to a range of mountains whose relative heights are represented by array A, as shown in a figure below. You have to choose how many flags you should take with you. The goal is to set the maximum number of flags on the peaks, according to certain rules.
Flags can only be set on peaks. What's more, if you take K flags, then the distance between any two flags should be greater than or equal to K. The distance between indices P and Q is the absolute value |P − Q|.
For example, given the mountain range represented by array A, above, with N = 12, if you take:
two flags, you can set them on peaks 1 and 5;
three flags, you can set them on peaks 1, 5 and 10;
four flags, you can set only three flags, on peaks 1, 5 and 10.
You can therefore set a maximum of three flags in this case.
Write a function:
def solution(A)
that, given a non-empty array A of N integers, returns the maximum number of flags that can be set on the peaks of the array.
For example, the following array A:
A[0] = 1
A[1] = 5
A[2] = 3
A[3] = 4
A[4] = 3
A[5] = 4
A[6] = 1
A[7] = 2
A[8] = 3
A[9] = 4
A[10] = 6
A[11] = 2
the function should return 3, as explained above.
N is an integer within the range [1..400,000];
each element of array A is an integer within the range [0..1,000,000,000].
상당히 어려운 문제였다. 풀이에 실패해 타인의 답을 공부했다. 지저분하게 나온 답들이 많아서 제일 깔끔하고 센스있게 푼 풀이를 가져왔다.
flag 수에 따라서 최소한으로 요구하는 배열크기는 아래와 같습니다.
1
X P X => 3
2
X P X P X => 5
3
X P XX P XX P X => 9
4
X P XXX P XXX P XXX P X => 15
5
X P XXXX P XXXX P XXXX P XXXX P X => 23
6
X P XXXXX P XXXXX P XXXXX P XXXXX P XXXXX P X => 33
최소 요구 배열크기(minimally required SizeOfArray)를 MRS(N)라고 할 때,
MRS(N) = MRS(N - 1) + (N - 1)*2 (when N > 1), MRS(1) = 3 라는 식이 성립합니다.
MRS(N) = (N - 1)*2 + (N - 2)*2 + (N - 3)*2 + ... + 3*2 + 2*2 + 1*2 + 3 = (N - 1)*(N - 1 + 1) + 3 = (N - 1)*N + 3
∴ MRS(N) = N^2 - N + 3 ≤ N^2 (when N ≥ 3)
대략적으로 MRS(N) = N^2라고 해도 무방합니다.
즉, 3개의 깃발이 필요할 때는, 최소한 배열의 사이즈는 9개 이상이여야 합니다.
반대로 사이즈에 따라서 최대로 가능한 깃발의 수는
MRS(N)의 역함수를 구하면 됩니다.
∴ MRS^{-1}(N) = N^{1/2} (N의 제곱근)
<example> MRS^{-1}(9) = 3, MRS^{-1}(16) = 4
따라서, 첫번째 peak와 마지막 peak의 차를 구하면 실질적인 배열의 수를 알 수 있고,
이 배열의 수에 제곱근을 한다면, 최대로 가능한 flat수를 알 수 있습니다.
대략적으로, MRS^{-1}(N) = N^{1/2}에서 +1을 하여 3.8xxx와 같은 값이 나올 때, 3 + 1로 최대 flag수를 지정하고 for문을 돌립니다.
<example> MPN(8) = 3, MPN(9) = 4, MPN(15) = 4, MPN(16) = 5
import math
def solution(A):
# 배열이 3보다 작은 경우는 peak를 구할 수 없으므로 0 return
if len(A) < 3:
return 0
# peak인 index를 담는 list
peak = []
for i in range(1, len(A)-1):
if A[i] > A[i-1] and A[i] > A[i+1]:
peak.append(i)
# peak가 2개 이하인 경우는 바로 return
if len(peak) < 3 :
return len(peak)
# 제일 처음 peak와 끝 peak 사이에 최대한 깃발을 꽂을 수 있는 갯수
maxflag = int(math.sqrt(peak[-1]-peak[0]))+1
# 제일처음 peak에서부터 조건을 비교하면서, count로 체크한 후 flag 수(f)를 return
for f in range(maxflag, 2, -1):
count = 1
p = peak[0]
for i, pe in enumerate(peak):
if f <= pe-p:
count += 1
p = pe
if count >= f:
break
return f