題目連結:
題目意譯:
你被給定一正整數陣列 nums。在一次操作中,你可以從 nums 中選擇任一數字出來並將其值減少到恰好一半。(注意到你可以在未來的操作中選擇這個減少後的數值。)
回傳使得將 nums 中數字之總和減少至少一半以下所需的最少操作數。
限制:
1 ≦ nums.length ≦ 10 ^ 5
1 ≦ nums[i] ≦ 10 ^ 7
範例測資:
範例 1:
輸入: nums = [5,19,8,1]
輸出: 3
解釋: nums 一開始的總和為 5 + 19 + 8 + 1 = 33。
以下為其中一個將其減少至少一半以下的方式之一:
選擇數字 19 並將其減少為 9.5。
選擇數字 9.5 並將其減少為 4.75。
選擇數字 8 並將其減少為 4。
最終的陣列為 [5, 4.75, 4, 1] 其總和為 5 + 4.75 + 4 + 1 = 14.75。
nums 之總和總共減少了 33 - 14.75 = 18.25,其值至少為初始總和的一半,即 18.25 ≧ 33 ÷ 2 = 16.5。
總結來說,我們使用了 3 次操作。因此我們回傳 3。
可以證明我們不能在少於 3 次操作之內將總和減少到至少一半。
範例 2:
輸入: nums = [3,8,20]
輸出: 3
解釋: nums 一開始的總和為 3 + 8 + 20 = 31。
以下為其中一個將其減少至少一半以下的方式之一:
選擇數字 20 並將其減少為 10。
選擇數字 10 並將其減少為 5。
選擇數字 3 並將其減少為 1.5。
最終的陣列為 [1.5, 8, 5] 其總和為 1.5 + 8 + 5 = 14.5。
nums 之總和總共減少了 31 - 14.5 = 16.5,其值至少為初始總和的一半,即 16.5 ≧ 31 ÷ 2 = 15.5。
總結來說,我們使用了 3 次操作。因此我們回傳 3。
可以證明我們不能在少於 3 次操作之內將總和減少到至少一半。
解題思維:
因為要減少操作數,因此每一次的操作應盡量減少越大的數值越好,因此每一次挑數字時候應該要挑越大的數字越好。
因此我們可以使用一個優先佇列(Priority Queue)來達成動態地維護當前最大值為何。因此我們就先行計算 nums 原始的總和,將其砍半後得到一個目標值 T,並在計算總和的過程中順便把所有數字丟進優先佇列中。
接著就重複以下步驟直到 nums 的新總和 < T 為止:
從優先佇列取出最大值(並將其刪除);
將該最大值砍半後丟回到優先佇列中。
上述過程中的重複次數即為所求最少所需操作數。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。