8787
8888### 方法一:二分查找
8989
90- 我们可以将题目可以转换为:对某个开销值,看它能不能在 maxOperations 次操作内得到。因此,二分枚举开销值,找到最小的且满足条件的开销值即可 。
90+ 本题需要我们最小化开销,即最小化单个袋子里球数目的最大值。随着最大值的增大,操作次数会减少,越容易满足条件 。
9191
92- 时间复杂度 $O(n \times \log M)$。其中 $n$ 和 $M$ 分别为数组 ` nums ` 的长度和最大值。
92+ 因此,我们可以二分枚举单个袋子里球数目的最大值,判断是否能在 $\textit{maxOperations}$ 次操作内得到。
93+
94+ 具体地,我们定义二分查找的左边界 $l = 1$,右边界 $r = \max(\textit{nums})$。然后我们不断二分枚举中间值 $\textit{mid} = \frac{l + r}{2}$,对于每个 $\textit{mid}$,我们计算在这个 $\textit{mid}$ 下,需要的操作次数。如果操作次数小于等于 $\textit{maxOperations}$,说明 $\textit{mid}$ 满足条件,我们将右边界 $r$ 更新为 $\textit{mid}$,否则将左边界 $l$ 更新为 $\textit{mid} + 1$。
95+
96+ 最后,我们返回左边界 $l$ 即可。
97+
98+ 时间复杂度 $O(n \times \log M)$,其中 $n$ 和 $M$ 分别是数组 $\textit{nums}$ 的长度和最大值。空间复杂度 $O(1)$。
9399
94100<!-- tabs:start -->
95101
@@ -101,31 +107,28 @@ class Solution:
101107 def check (mx : int ) -> bool :
102108 return sum ((x - 1 ) // mx for x in nums) <= maxOperations
103109
104- return bisect_left(range (1 , max (nums)), True , key = check) + 1
110+ return bisect_left(range (1 , max (nums) + 1 ), True , key = check) + 1
105111```
106112
107113#### Java
108114
109115``` java
110116class Solution {
111117 public int minimumSize (int [] nums , int maxOperations ) {
112- int left = 1 , right = 0 ;
113- for (int x : nums) {
114- right = Math . max(right, x);
115- }
116- while (left < right) {
117- int mid = (left + right) >> 1 ;
118- long cnt = 0 ;
118+ int l = 1 , r = Arrays . stream(nums). max(). getAsInt();
119+ while (l < r) {
120+ int mid = (l + r) >> 1 ;
121+ long s = 0 ;
119122 for (int x : nums) {
120- cnt += (x - 1 ) / mid;
123+ s += (x - 1 ) / mid;
121124 }
122- if (cnt <= maxOperations) {
123- right = mid;
125+ if (s <= maxOperations) {
126+ r = mid;
124127 } else {
125- left = mid + 1 ;
128+ l = mid + 1 ;
126129 }
127130 }
128- return left ;
131+ return l ;
129132 }
130133}
131134```
@@ -136,20 +139,20 @@ class Solution {
136139class Solution {
137140public:
138141 int minimumSize(vector<int >& nums, int maxOperations) {
139- int left = 1, right = * max_element (nums.begin(), nums.end() );
140- while (left < right ) {
141- int mid = (left + right ) >> 1;
142- long long cnt = 0;
142+ int l = 1, r = ranges::max (nums);
143+ while (l < r ) {
144+ int mid = (l + r ) >> 1;
145+ long long s = 0;
143146 for (int x : nums) {
144- cnt += (x - 1) / mid;
147+ s += (x - 1) / mid;
145148 }
146- if (cnt <= maxOperations) {
147- right = mid;
149+ if (s <= maxOperations) {
150+ r = mid;
148151 } else {
149- left = mid + 1;
152+ l = mid + 1;
150153 }
151154 }
152- return left ;
155+ return l ;
153156 }
154157};
155158```
@@ -161,11 +164,11 @@ func minimumSize(nums []int, maxOperations int) int {
161164 r := slices.Max(nums)
162165 return 1 + sort.Search(r, func(mx int) bool {
163166 mx++
164- cnt := 0
167+ s := 0
165168 for _, x := range nums {
166- cnt += (x - 1) / mx
169+ s += (x - 1) / mx
167170 }
168- return cnt <= maxOperations
171+ return s <= maxOperations
169172 })
170173}
171174```
@@ -174,21 +177,45 @@ func minimumSize(nums []int, maxOperations int) int {
174177
175178``` ts
176179function minimumSize(nums : number [], maxOperations : number ): number {
177- let left = 1 ;
178- let right = Math .max (... nums );
179- while (left < right ) {
180- const mid = (left + right ) >> 1 ;
181- let cnt = 0 ;
182- for (const x of nums ) {
183- cnt += ~~ ((x - 1 ) / mid );
184- }
185- if (cnt <= maxOperations ) {
186- right = mid ;
180+ let [l, r] = [1 , Math .max (... nums )];
181+ while (l < r ) {
182+ const mid = (l + r ) >> 1 ;
183+ const s = nums .map (x => ((x - 1 ) / mid ) | 0 ).reduce ((a , b ) => a + b );
184+ if (s <= maxOperations ) {
185+ r = mid ;
187186 } else {
188- left = mid + 1 ;
187+ l = mid + 1 ;
189188 }
190189 }
191- return left ;
190+ return l ;
191+ }
192+ ```
193+
194+ #### Rust
195+
196+ ``` rust
197+ impl Solution {
198+ pub fn minimum_size (nums : Vec <i32 >, max_operations : i32 ) -> i32 {
199+ let mut l = 1 ;
200+ let mut r = * nums . iter (). max (). unwrap ();
201+
202+ while l < r {
203+ let mid = (l + r ) / 2 ;
204+ let mut s : i64 = 0 ;
205+
206+ for & x in & nums {
207+ s += ((x - 1 ) / mid ) as i64 ;
208+ }
209+
210+ if s <= max_operations as i64 {
211+ r = mid ;
212+ } else {
213+ l = mid + 1 ;
214+ }
215+ }
216+
217+ l
218+ }
192219}
193220```
194221
@@ -201,24 +228,43 @@ function minimumSize(nums: number[], maxOperations: number): number {
201228 * @return {number}
202229 */
203230var minimumSize = function (nums , maxOperations ) {
204- let left = 1 ;
205- let right = Math .max (... nums);
206- while (left < right) {
207- const mid = (left + right) >> 1 ;
208- let cnt = 0 ;
209- for (const x of nums) {
210- cnt += ~~ ((x - 1 ) / mid);
211- }
212- if (cnt <= maxOperations) {
213- right = mid;
231+ let [l, r] = [1 , Math .max (... nums)];
232+ while (l < r) {
233+ const mid = (l + r) >> 1 ;
234+ const s = nums .map (x => ((x - 1 ) / mid) | 0 ).reduce ((a , b ) => a + b);
235+ if (s <= maxOperations) {
236+ r = mid;
214237 } else {
215- left = mid + 1 ;
238+ l = mid + 1 ;
216239 }
217240 }
218- return left ;
241+ return l ;
219242};
220243```
221244
245+ #### C#
246+
247+ ``` cs
248+ public class Solution {
249+ public int MinimumSize (int [] nums , int maxOperations ) {
250+ int l = 1 , r = nums .Max ();
251+ while (l < r ) {
252+ int mid = (l + r ) >> 1 ;
253+ long s = 0 ;
254+ foreach (int x in nums ) {
255+ s += (x - 1 ) / mid ;
256+ }
257+ if (s <= maxOperations ) {
258+ r = mid ;
259+ } else {
260+ l = mid + 1 ;
261+ }
262+ }
263+ return l ;
264+ }
265+ }
266+ ```
267+
222268<!-- tabs: end -->
223269
224270<!-- solution: end -->
0 commit comments