題目連結:
題目意譯:
你被給定一個上頭寫有編號的球之集合,並被要求盡可能地平均地將這些球分到一些箱子裡。有兩個規則你必須遵守:
同一箱子裡的球的編號要一致。不過,多個相同編號的球可以分到不同的箱子。
球數最多的箱子恰好只能比球數最少的箱子多一顆球。
回傳根據這些規則來分裝這些球最少所需的箱子數。
限制:
1 ≦ nums.length ≦ 10 ^ 5
1 ≦ nums[i] ≦ 10 ^ 9
範例測資:
範例 1:
輸入:balls = [3,2,3,2,3]
輸出:2
解釋:
我們可以根據以下方式分裝這些球:
[3,3,3]
[2,2]
兩箱子的球數差別沒有超過 1。
範例 2:
輸入:balls = [10,10,10,3,1,1]
輸出:4
解釋:
我們可以根據以下方式分裝這些球:
[10]
[10,10]
[3]
[1,1]
你無法在遵守規則的情況下使用更少的箱子。例如說,將三顆編號 10 的球全部改放到同一箱將會違反箱子球數差的規則。
解題思維:
首先,掃過一次 balls 並統計每一種編號的個數(可以用雜湊表(Hash Table)或其他資料結構與方式)。
接著假設在最佳策略中球數最大的箱子有 x 顆球,則每一種編號的球會被分裝到若干箱恰好 x 顆球的箱子以及若干箱恰好 x - 1 顆球的箱子。既然我們不知道 x 是什麼,那就每一種都試試看。可以看到最多只要試 1 ~ balls.length 這幾種數字即可。
再假設現在某一種編號的球有 C 顆,且球數最多的箱子有 x 顆球。很明顯地,當 C 可以被 x 整除時,所需的最少箱子就是 C / x;比較不明顯的是當 C 無法被 x 整除的時候,此時這些球「有可能」可以被分成若干箱 x - 1 以及若干箱 x,而且可能有多種可行的方式。
那要怎麼快速地檢查可不可行以及最少需要多少箱子呢?首先計算盡量裝成 x 顆的箱子會有幾箱,即 C / x 取整數部份,稱其值為 b。而剩下的球數之值稱為 r。
由於 C 無法被 x 整除,因此至少會有一個箱子是裝 x - 1 顆球(如果真的可行的話)。因此我們可以先把剩下的 r 顆球丟進這個箱子裡。所以我們還需要 x - 1 - r 顆球。
而此時如果我們把某一箱裝 x 顆球的箱子換成裝 x - 1 顆,則它將會多剩一顆球出來。也因此如果 b < x - 1 - r,則代表著無解。
反之如果 b ≧ x - 1 - r,則將其中 x - 1 - r 個裝 x 顆球的箱子換成裝 x - 1 顆,而多出來的球便可以與原先的 r 顆球結合而多裝一箱裝有 x - 1 顆球的箱子。進而代表著我們可以將所有球都裝進裝有 x 或是 x - 1 顆球的箱子。而這會是最少所需的箱子,即 b + 1 箱。
而可以看到對於數量為 C 的編號球,對於它來說合法的 x 值只會可能是 1 ~ C + 1 而已,因為再上去也不可能裝箱成功。因此對於每一種編號不需要窮舉 1 ~ balls.length 來檢查。
最後只要掃過 1 ~ balls.length(也可以將上界從 balls.length 限縮到最大的「C + 1」之值,但不影響時間複雜度)然後檢查每一種 x 值對於每一種編號可不可行(上面窮舉 x 並檢查的過程可以統計多少種編號可行,然後在這邊檢查可行種類數是否與全部編號的種類數相等)。將其中可行的那幾個 x 值取最少所需的箱子數即為所求。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。