@@ -75,32 +75,222 @@ tags:
75
75
76
76
<!-- solution:start -->
77
77
78
- ### 方法一
78
+ ### 方法一:二分查找
79
+
80
+ 我们可以二分枚举乘积的值 $p$,定义二分的区间为 $[ l, r] $,其中 $l = -\text{max}(|\text{nums1}[ 0] |, |\text{nums1}[ n - 1] |) \times \text{max}(|\text{nums2}[ 0] |, |\text{nums2}[ n - 1] |)$, $r = -l$。
81
+
82
+ 对于每个 $p$,我们计算出乘积小于等于 $p$ 的乘积的个数,如果这个个数大于等于 $k$,那么说明第 $k$ 小的乘积一定小于等于 $p$,我们就可以将区间右端点缩小到 $p$,否则我们将区间左端点增大到 $p + 1$。
83
+
84
+ 那么问题的关键就是如何计算乘积小于等于 $p$ 的乘积的个数。我们可以枚举 $\text{nums1}$ 中的每个数 $x$,分类讨论:
85
+
86
+ - 如果 $x > 0$,那么 $x \times \text{nums2}[ i] $ 随着 $i$ 的增大是单调递增的,我们可以使用二分查找找到最小的 $i$,使得 $x \times \text{nums2}[ i] > p$,那么 $i$ 就是小于等于 $p$ 的乘积的个数,累加到个数 $\text{cnt}$ 中;
87
+ - 如果 $x < 0$,那么 $x \times \text{nums2}[ i] $ 随着 $i$ 的增大是单调递减的,我们可以使用二分查找找到最小的 $i$,使得 $x \times \text{nums2}[ i] \leq p$,那么 $n - i$ 就是小于等于 $p$ 的乘积的个数,累加到个数 $\text{cnt}$ 中;
88
+ - 如果 $x = 0$,那么 $x \times \text{nums2}[ i] = 0$,如果 $p \geq 0$,那么 $n$ 就是小于等于 $p$ 的乘积的个数,累加到个数 $\text{cnt}$ 中。
89
+
90
+ 这样我们就可以通过二分查找找到第 $k$ 小的乘积。
91
+
92
+ 时间复杂度 $O(m \times \log n \times \log M)$,其中 $m$ 和 $n$ 分别为 $\text{nums1}$ 和 $\text{nums2}$ 的长度,而 $M$ 为 $\text{nums1}$ 和 $\text{nums2}$ 中的最大值的绝对值。
79
93
80
94
<!-- tabs:start -->
81
95
82
96
#### Python3
83
97
84
98
``` python
85
-
99
+ class Solution :
100
+ def kthSmallestProduct (self , nums1 : List[int ], nums2 : List[int ], k : int ) -> int :
101
+ def count (p : int ) -> int :
102
+ cnt = 0
103
+ n = len (nums2)
104
+ for x in nums1:
105
+ if x > 0 :
106
+ cnt += bisect_right(nums2, p / x)
107
+ elif x < 0 :
108
+ cnt += n - bisect_left(nums2, p / x)
109
+ else :
110
+ cnt += n * int (p >= 0 )
111
+ return cnt
112
+
113
+ mx = max (abs (nums1[0 ]), abs (nums1[- 1 ])) * max (abs (nums2[0 ]), abs (nums2[- 1 ]))
114
+ return bisect_left(range (- mx, mx + 1 ), k, key = count) - mx
86
115
```
87
116
88
117
#### Java
89
118
90
119
``` java
91
-
120
+ class Solution {
121
+ private int [] nums1;
122
+ private int [] nums2;
123
+
124
+ public long kthSmallestProduct (int [] nums1 , int [] nums2 , long k ) {
125
+ this . nums1 = nums1;
126
+ this . nums2 = nums2;
127
+ int m = nums1. length;
128
+ int n = nums2. length;
129
+ int a = Math . max(Math . abs(nums1[0 ]), Math . abs(nums1[m - 1 ]));
130
+ int b = Math . max(Math . abs(nums2[0 ]), Math . abs(nums2[n - 1 ]));
131
+ long r = (long ) a * b;
132
+ long l = (long ) - a * b;
133
+ while (l < r) {
134
+ long mid = (l + r) >> 1 ;
135
+ if (count(mid) >= k) {
136
+ r = mid;
137
+ } else {
138
+ l = mid + 1 ;
139
+ }
140
+ }
141
+ return l;
142
+ }
143
+
144
+ private long count (long p ) {
145
+ long cnt = 0 ;
146
+ int n = nums2. length;
147
+ for (int x : nums1) {
148
+ if (x > 0 ) {
149
+ int l = 0 , r = n;
150
+ while (l < r) {
151
+ int mid = (l + r) >> 1 ;
152
+ if ((long ) x * nums2[mid] > p) {
153
+ r = mid;
154
+ } else {
155
+ l = mid + 1 ;
156
+ }
157
+ }
158
+ cnt += l;
159
+ } else if (x < 0 ) {
160
+ int l = 0 , r = n;
161
+ while (l < r) {
162
+ int mid = (l + r) >> 1 ;
163
+ if ((long ) x * nums2[mid] <= p) {
164
+ r = mid;
165
+ } else {
166
+ l = mid + 1 ;
167
+ }
168
+ }
169
+ cnt += n - l;
170
+ } else if (p >= 0 ) {
171
+ cnt += n;
172
+ }
173
+ }
174
+ return cnt;
175
+ }
176
+ }
92
177
```
93
178
94
179
#### C++
95
180
96
181
``` cpp
97
-
182
+ class Solution {
183
+ public:
184
+ long long kthSmallestProduct(vector<int >& nums1, vector<int >& nums2, long long k) {
185
+ int m = nums1.size(), n = nums2.size();
186
+ int a = max(abs(nums1[ 0] ), abs(nums1[ m - 1] ));
187
+ int b = max(abs(nums2[ 0] ), abs(nums2[ n - 1] ));
188
+ long long r = 1LL * a * b;
189
+ long long l = -r;
190
+ auto count = [ &] (long long p) {
191
+ long long cnt = 0;
192
+ for (int x : nums1) {
193
+ if (x > 0) {
194
+ int l = 0, r = n;
195
+ while (l < r) {
196
+ int mid = (l + r) >> 1;
197
+ if (1LL * x * nums2[ mid] > p) {
198
+ r = mid;
199
+ } else {
200
+ l = mid + 1;
201
+ }
202
+ }
203
+ cnt += l;
204
+ } else if (x < 0) {
205
+ int l = 0, r = n;
206
+ while (l < r) {
207
+ int mid = (l + r) >> 1;
208
+ if (1LL * x * nums2[ mid] <= p) {
209
+ r = mid;
210
+ } else {
211
+ l = mid + 1;
212
+ }
213
+ }
214
+ cnt += n - l;
215
+ } else if (p >= 0) {
216
+ cnt += n;
217
+ }
218
+ }
219
+ return cnt;
220
+ };
221
+ while (l < r) {
222
+ long long mid = (l + r) >> 1;
223
+ if (count(mid) >= k) {
224
+ r = mid;
225
+ } else {
226
+ l = mid + 1;
227
+ }
228
+ }
229
+ return l;
230
+ }
231
+ };
98
232
```
99
233
100
234
#### Go
101
235
102
236
```go
103
-
237
+ func kthSmallestProduct(nums1 []int, nums2 []int, k int64) int64 {
238
+ m := len(nums1)
239
+ n := len(nums2)
240
+ a := max(abs(nums1[0]), abs(nums1[m-1]))
241
+ b := max(abs(nums2[0]), abs(nums2[n-1]))
242
+ r := int64(a) * int64(b)
243
+ l := -r
244
+
245
+ count := func(p int64) int64 {
246
+ var cnt int64
247
+ for _, x := range nums1 {
248
+ if x > 0 {
249
+ l, r := 0, n
250
+ for l < r {
251
+ mid := (l + r) >> 1
252
+ if int64(x)*int64(nums2[mid]) > p {
253
+ r = mid
254
+ } else {
255
+ l = mid + 1
256
+ }
257
+ }
258
+ cnt += int64(l)
259
+ } else if x < 0 {
260
+ l, r := 0, n
261
+ for l < r {
262
+ mid := (l + r) >> 1
263
+ if int64(x)*int64(nums2[mid]) <= p {
264
+ r = mid
265
+ } else {
266
+ l = mid + 1
267
+ }
268
+ }
269
+ cnt += int64(n - l)
270
+ } else if p >= 0 {
271
+ cnt += int64(n)
272
+ }
273
+ }
274
+ return cnt
275
+ }
276
+
277
+ for l < r {
278
+ mid := (l + r) >> 1
279
+ if count(mid) >= k {
280
+ r = mid
281
+ } else {
282
+ l = mid + 1
283
+ }
284
+ }
285
+ return l
286
+ }
287
+
288
+ func abs(x int) int {
289
+ if x < 0 {
290
+ return -x
291
+ }
292
+ return x
293
+ }
104
294
```
105
295
106
296
<!-- tabs: end -->
0 commit comments