このアルゴリズムの分析をより面白くするために、次の入力を行います。
9
2
3
4
4
4
2
1
3
4
まず、子供がキャンディーを手に入れている子供の隣に座っていてx
、その子供が低い評価を持っている場合、最初の子供は少なくともx+1
キャンディーを手に入れる必要があることに注意してください。違いを1以上にすると、キャンディーが無駄になります。差は1より大きい必要がある場合もありますが、後でそれが発生したときに説明します。
さて、キャンディーを1つだけ手に入れるべき子供たちを見つけましょう。私は、評価を山脈として視覚化し(評価が大きいほど、その時点で山が高くなります)、1つのキャンディーを取得する必要がある子供を見つけることは、山の谷(両方の隣人がより高い評価または同じ評価を持つポイント)を見つけることとして視覚化します。範囲。与えられた例は次のようになります(谷は矢印で示されています):
*** *
**** **
****** **
*********
^ ^ ^
このプロセスの目的のために、この線の開始前と終了後に「無限」の高さの2つのピークがあると仮定します。(私が無限と言うときは、入力で可能な値よりも大きいことを意味するので10^5+1
、「無限」に使用できます。実際には、問題設定者が入力データにバグを持っている場合に備えて、それよりも大きい値を使用します。)
次のコードを使用して、谷を簡単に見つけることができます。
ratings = ...
N = ...
valleys = []
def get_rating(i):
if i < 0 or i > N-1:
return INFINITY
return ratings[i]
for i from 0 to N-1:
if get_rating(i) <= get_rating(i-1) and get_rating(i) <= get_rating(i+1):
valleys.append(i)
配列valleys
には谷のインデックスが含まれています。私たちは、谷を代表する各子供が1つのキャンディーを手に入れるべきであることを知っています。説明のために、谷がインデックス4にあると仮定します。これで、インデックス3と5の子供は少なくとも2つのキャンディーを入手する必要があることがわかりました。インデックス2の子供がインデックス3の子供よりも高い評価を持っている場合、その子供は少なくとも3つのキャンディーを手に入れる必要があります。2以下の場合も同様です。同様に6以上の場合。
私が「少なくとも」と言っていることに注意してください。これはピークが原因です(評価が隣人の両方よりも高い子供、谷とは異なり、この定義に平等を含めないことに注意してください)。ピークには2つの最小制約があり、2つのうち大きい方を選択するだけです。
これで、次のコードを使用して、各子供が手に入れるべきキャンディーの数を見つけることができます。
candies = [0] * N # An array of N 0s
for valley_idx in valleys:
candies[valley_idx] = 1
cur_idx = valley_idx-1
cur_candies = 2
while cur_idx >= 0 and ratings[cur_idx] > ratings[cur_idx+1]:
candies[cur_idx] = max(candies[cur_idx], cur_candies)
cur_idx -= 1
cur_candies += 1
cur_idx = valley_idx+1
cur_candies = 2
while cur_idx < N and ratings[cur_idx] > ratings[cur_idx-1]:
candies[cur_idx] = max(candies[cur_idx], cur_candies)
cur_idx += 1
cur_candies += 1
candies
次に、教師が購入する必要のあるキャンディーの数は、配列内の値の合計です。
これを行うと、答えは18
サンプル入力またはグラフの形式であることがわかります。
* * *
** ** **
*********
わずかに変更された問題ステートメントの解決策
上記の解決策では、同じ評価の隣接する子供は、他の子供との関係で取得するキャンディーの量に制限を設けないと仮定しました。代わりに、両方の子供が同じ量のキャンディーを入手する必要がある場合は、これを考慮してアルゴリズムを非常に簡単に変更できます。
基本的な考え方は、ある種のランレングスエンコーディングを行うことです。これは、同じ評価の子供が1人以上連続しているかどうかに関係なく、隣人が取得するキャンディーの量が変わらないことに気付くためです。5人の子供が5人のキャンディーを手に入れるということは、5人だけでなく、25人のキャンディーを配らなければならないことを意味するので、私たちは連続した子供の数を追跡する必要がありますmultipliers
。次のコードを使用して、新しいratings
配列と配列を見つけますmultipliers
。
new_ratings = [ratings[0]]
multipliers = [1]
for i from 1 to N-1:
if ratings[i] == new_ratings[len(new_ratings)-1]:
multipliers[len(new_ratings)-1] += 1
else:
new_ratings.append(ratings[i])
multipliers.append(1)
ここで、配列に対して元のアルゴリズムを実行し、new_ratings
配列を取得しcandies
ます。次に、実際に実行できるキャンディーの量を取得します。
answer = 0
for i from 0 to len(new_ratings)-1:
answer += multipliers[i] * candies[i]
これを行うと、答えは20
サンプル入力またはグラフの形式であることがわかります。
*** *
***** **
*********