64
64
65
65
### 方法一:二分查找
66
66
67
- 先对 position 进行排序 。
67
+ 我们注意到,任意两球间的最小磁力越大,能够放入的球的数量就越少,这存在着单调性。我们可以使用二分查找,找到最大的最小磁力,使得能够放入的球的数量不小于 $m$ 。
68
68
69
- 然后二分枚举磁力值(相邻两球的最小间距),统计当前最小磁力值下能放下多少个小球,记为 cnt。若 ` cnt >= m ` ,说明此磁力值符合条件。继续二分查找,最终找到符合条件的最大磁力值。
69
+ 我们首先对篮子的位置进行排序,然后使用二分查找的方法,定义二分查找的左边界 $l = 1$,右边界 $r = \text{position}[ n - 1] $,其中 $n$ 为篮子的数量。在每次二分查找的过程中,我们计算取中值 $m = (l + r + 1) / 2$,然后判断是否存在一种放置球的方法,使得能够放入的球的数量不小于 $m$。
70
+
71
+ 问题转换为判断一个给定的最小磁力 $f$ 是否能够放入 $m$ 个球。我们可以从左到右遍历篮子的位置,如果上一个球的位置与当前篮子的位置的距离大于等于 $f$,则说明可以在当前篮子放置一个球。最后判断放置的球的数量是否不小于 $m$ 即可。
72
+
73
+ 时间复杂度 $O(n \times \log n + n \times \log M)$,空间复杂度 $O(\log n)$。其中 $n$ 和 $M$ 分别为篮子的数量和篮子的位置的最大值。
70
74
71
75
<!-- tabs:start -->
72
76
@@ -75,56 +79,51 @@ tags:
75
79
``` python
76
80
class Solution :
77
81
def maxDistance (self , position : List[int ], m : int ) -> int :
78
- def check (f ) :
79
- prev = position[ 0 ]
80
- cnt = 1
81
- for curr in position[ 1 :] :
82
+ def check (f : int ) -> bool :
83
+ prev = - inf
84
+ cnt = 0
85
+ for curr in position:
82
86
if curr - prev >= f:
83
87
prev = curr
84
88
cnt += 1
85
- return cnt >= m
89
+ return cnt < m
86
90
87
91
position.sort()
88
- left, right = 1 , position[- 1 ]
89
- while left < right:
90
- mid = (left + right + 1 ) >> 1
91
-
92
- if check(mid):
93
- left = mid
94
- else :
95
- right = mid - 1
96
- return left
92
+ l, r = 1 , position[- 1 ]
93
+ return bisect_left(range (l, r + 1 ), True , key = check)
97
94
```
98
95
99
96
#### Java
100
97
101
98
``` java
102
99
class Solution {
100
+ private int [] position;
101
+
103
102
public int maxDistance (int [] position , int m ) {
104
103
Arrays . sort(position);
105
- int left = 1 , right = position[position. length - 1 ];
106
- while (left < right) {
107
- int mid = (left + right + 1 ) >>> 1 ;
108
- if (check(position, mid, m)) {
109
- left = mid;
104
+ this . position = position;
105
+ int l = 1 , r = position[position. length - 1 ];
106
+ while (l < r) {
107
+ int mid = (l + r + 1 ) >> 1 ;
108
+ if (count(mid) >= m) {
109
+ l = mid;
110
110
} else {
111
- right = mid - 1 ;
111
+ r = mid - 1 ;
112
112
}
113
113
}
114
- return left ;
114
+ return l ;
115
115
}
116
116
117
- private boolean check (int [] position , int f , int m ) {
117
+ private int count (int f ) {
118
118
int prev = position[0 ];
119
119
int cnt = 1 ;
120
- for (int i = 1 ; i < position. length; ++ i) {
121
- int curr = position[i];
120
+ for (int curr : position) {
122
121
if (curr - prev >= f) {
123
- prev = curr;
124
122
++ cnt;
123
+ prev = curr;
125
124
}
126
125
}
127
- return cnt >= m ;
126
+ return cnt;
128
127
}
129
128
}
130
129
```
@@ -136,28 +135,27 @@ class Solution {
136
135
public:
137
136
int maxDistance(vector<int >& position, int m) {
138
137
sort(position.begin(), position.end());
139
- int left = 1, right = position[ position.size() - 1] ;
140
- while (left < right) {
141
- int mid = (left + right + 1) >> 1;
142
- if (check(position, mid, m))
143
- left = mid;
144
- else
145
- right = mid - 1;
146
- }
147
- return left;
148
- }
149
-
150
- bool check(vector<int>& position, int f, int m) {
151
- int prev = position[0];
152
- int cnt = 1;
153
- for (int i = 1; i < position.size(); ++i) {
154
- int curr = position[i];
155
- if (curr - prev >= f) {
156
- prev = curr;
157
- ++cnt;
138
+ int l = 1, r = position.back();
139
+ auto count = [ &] (int f) {
140
+ int prev = position[ 0] ;
141
+ int cnt = 1;
142
+ for (int& curr : position) {
143
+ if (curr - prev >= f) {
144
+ prev = curr;
145
+ cnt++;
146
+ }
147
+ }
148
+ return cnt;
149
+ };
150
+ while (l < r) {
151
+ int mid = (l + r + 1) >> 1;
152
+ if (count(mid) >= m) {
153
+ l = mid;
154
+ } else {
155
+ r = mid - 1;
158
156
}
159
157
}
160
- return cnt >= m ;
158
+ return l ;
161
159
}
162
160
};
163
161
```
@@ -167,26 +165,46 @@ public:
167
165
```go
168
166
func maxDistance(position []int, m int) int {
169
167
sort.Ints(position)
170
- left , right := 1 , position[len (position)-1 ]
171
- check := func (f int ) bool {
172
- prev , cnt := position[ 0 ], 1
173
- for _ , curr := range position[ 1 :] {
168
+ return sort.Search( position[len(position)-1], func(f int) bool {
169
+ prev := position[0]
170
+ cnt := 1
171
+ for _, curr := range position {
174
172
if curr-prev >= f {
175
- prev = curr
176
173
cnt++
174
+ prev = curr
177
175
}
178
176
}
179
- return cnt >= m
180
- }
181
- for left < right {
182
- mid := (left + right + 1 ) >> 1
183
- if check (mid) {
184
- left = mid
185
- } else {
186
- right = mid - 1
187
- }
188
- }
189
- return left
177
+ return cnt < m
178
+ }) - 1
179
+ }
180
+ ```
181
+
182
+ #### TypeScript
183
+
184
+ ``` ts
185
+ function maxDistance(position : number [], m : number ): number {
186
+ position .sort ((a , b ) => a - b );
187
+ let [l, r] = [1 , position .at (- 1 )! ];
188
+ const count = (f : number ): number => {
189
+ let cnt = 1 ;
190
+ let prev = position [0 ];
191
+ for (const curr of position ) {
192
+ if (curr - prev >= f ) {
193
+ cnt ++ ;
194
+ prev = curr ;
195
+ }
196
+ }
197
+ return cnt ;
198
+ };
199
+ while (l < r ) {
200
+ const mid = (l + r + 1 ) >> 1 ;
201
+ if (count (mid ) >= m ) {
202
+ l = mid ;
203
+ } else {
204
+ r = mid - 1 ;
205
+ }
206
+ }
207
+ return l ;
190
208
}
191
209
```
192
210
@@ -199,32 +217,28 @@ func maxDistance(position []int, m int) int {
199
217
* @return {number}
200
218
*/
201
219
var maxDistance = function (position , m ) {
202
- position .sort ((a , b ) => {
203
- return a - b;
204
- });
205
- let left = 1 ,
206
- right = position[position .length - 1 ];
207
- const check = function (f ) {
208
- let prev = position[0 ];
220
+ position .sort ((a , b ) => a - b);
221
+ let [l, r] = [1 , position .at (- 1 )];
222
+ const count = f => {
209
223
let cnt = 1 ;
210
- for ( let i = 1 ; i < position . length ; ++ i) {
211
- const curr = position[i];
224
+ let prev = position[ 0 ];
225
+ for ( const curr of position) {
212
226
if (curr - prev >= f) {
227
+ cnt++ ;
213
228
prev = curr;
214
- ++ cnt;
215
229
}
216
230
}
217
- return cnt >= m ;
231
+ return cnt;
218
232
};
219
- while (left < right ) {
220
- const mid = (left + right + 1 ) >> 1 ;
221
- if (check (mid)) {
222
- left = mid;
233
+ while (l < r ) {
234
+ const mid = (l + r + 1 ) >> 1 ;
235
+ if (count (mid) >= m ) {
236
+ l = mid;
223
237
} else {
224
- right = mid - 1 ;
238
+ r = mid - 1 ;
225
239
}
226
240
}
227
- return left ;
241
+ return l ;
228
242
};
229
243
```
230
244
0 commit comments