67
67
68
68
<!-- 这里可写通用的实现逻辑 -->
69
69
70
- 二分查找。
70
+ ** 方法一: 二分查找**
71
71
72
- 二分枚举运载能力 capacity,找到能在 D 天内送达的最小运载。
72
+ 我们注意到,如果运载能力 $x$ 能够在 $days$ 天内运送完所有包裹,那么运载能力 $x + 1$ 也能在 $days$ 天内运送完所有包裹。也即是说,随着运载能力的增加,运送天数只会减少,不会增加。这存在一个单调性,因此我们可以使用二分查找的方法来寻找最小的运载能力。
73
+
74
+ 我们定义二分查找的左边界 $left= \max\limits_ {i=0}^{n-1} weights[ i] $,右边界 $right = \sum\limits_ {i=0}^{n-1} weights[ i] $。然后二分枚举运载能力 $x$,判断是否能在 $days$ 天内运送完所有包裹。如果能,那么我们将右边界调整为 $x$,否则将左边界调整为 $x + 1$。
75
+
76
+ 判断是否能在 $days$ 天内运送完所有包裹的方法是,我们从左到右遍历包裹,将当前包裹加入当前运载能力的船上,如果当前船的运载能力超过了 $x$,那么我们将当前包裹放到下一天的船上,同时天数加一。如果天数超过了 $days$,那么我们返回 $false$,否则返回 $true$。
77
+
78
+ 时间复杂度 $O(n \times \log \sum\limits_ {i=0}^{n-1} weights[ i] )$,空间复杂度 $O(1)$。其中 $n$ 为包裹数量。
73
79
74
80
<!-- tabs:start -->
75
81
79
85
80
86
``` python
81
87
class Solution :
82
- def shipWithinDays (self , weights : List[int ], D : int ) -> int :
83
- def check (capacity ):
84
- cnt, t = 1 , 0
88
+ def shipWithinDays (self , weights : List[int ], days : int ) -> int :
89
+ def check (mx ):
90
+ ws, cnt = 0 , 1
85
91
for w in weights:
86
- if w > capacity:
87
- return False
88
- if t + w <= capacity:
89
- t += w
90
- else :
92
+ ws += w
93
+ if ws > mx:
91
94
cnt += 1
92
- t = w
93
- return cnt <= D
94
-
95
- left, right = 1 , 25000000
96
- while left < right:
97
- mid = (left + right) >> 1
98
- if check(mid):
99
- right = mid
100
- else :
101
- left = mid + 1
102
- return left
95
+ ws = w
96
+ return cnt <= days
97
+
98
+ left, right = max (weights), sum (weights) + 1
99
+ return left + bisect_left(range (left, right), True , key = check)
103
100
```
104
101
105
102
### ** Java**
@@ -109,10 +106,14 @@ class Solution:
109
106
``` java
110
107
class Solution {
111
108
public int shipWithinDays (int [] weights , int days ) {
112
- int left = 1 , right = Integer . MAX_VALUE ;
109
+ int left = 0 , right = 0 ;
110
+ for (int w : weights) {
111
+ left = Math . max(left, w);
112
+ right += w;
113
+ }
113
114
while (left < right) {
114
115
int mid = (left + right) >> 1 ;
115
- if (canCarry(weights, days, mid )) {
116
+ if (check(mid, weights, days )) {
116
117
right = mid;
117
118
} else {
118
119
left = mid + 1 ;
@@ -121,21 +122,16 @@ class Solution {
121
122
return left;
122
123
}
123
124
124
- public boolean canCarry (int [] weights , int days , int carry ) {
125
- int useDay = 1 ;
126
- int curCarry = 0 ;
127
- for (int weight : weights) {
128
- if (weight > carry) {
129
- return false ;
130
- }
131
- if ((carry - curCarry) >= weight) {
132
- curCarry += weight;
133
- } else {
134
- curCarry = weight;
135
- useDay++ ;
125
+ private boolean check (int mx , int [] weights , int days ) {
126
+ int ws = 0 , cnt = 1 ;
127
+ for (int w : weights) {
128
+ ws += w;
129
+ if (ws > mx) {
130
+ ws = w;
131
+ ++ cnt;
136
132
}
137
133
}
138
- return useDay <= days;
134
+ return cnt <= days;
139
135
}
140
136
}
141
137
```
@@ -146,66 +142,92 @@ class Solution {
146
142
class Solution {
147
143
public:
148
144
int shipWithinDays(vector<int >& weights, int days) {
149
- int left = 1, right = 25000000;
145
+ int left = 0, right = 0;
146
+ for (auto& w : weights) {
147
+ left = max(left, w);
148
+ right += w;
149
+ }
150
+ auto check = [ &] (int mx) {
151
+ int ws = 0, cnt = 1;
152
+ for (auto& w : weights) {
153
+ ws += w;
154
+ if (ws > mx) {
155
+ ws = w;
156
+ ++cnt;
157
+ }
158
+ }
159
+ return cnt <= days;
160
+ };
150
161
while (left < right) {
151
- int mid = left + right >> 1;
152
- if (check(weights, days, mid)) {
162
+ int mid = ( left + right) >> 1;
163
+ if (check(mid)) {
153
164
right = mid;
154
165
} else {
155
166
left = mid + 1;
156
167
}
157
168
}
158
169
return left;
159
170
}
160
-
161
- bool check(vector<int>& weights, int days, int capacity) {
162
- int cnt = 1, t = 0;
163
- for (auto w : weights) {
164
- if (w > capacity) {
165
- return false;
166
- }
167
- if (t + w <= capacity) {
168
- t += w;
169
- } else {
170
- ++cnt;
171
- t = w;
172
- }
173
- }
174
- return cnt <= days;
175
- }
176
171
};
177
172
```
178
173
179
174
### **Go**
180
175
181
176
```go
182
177
func shipWithinDays(weights []int, days int) int {
183
- left , right := 1 , 25000000
184
- for left < right {
185
- mid := (left + right) >> 1
186
- if check (weights, days, mid) {
187
- right = mid
188
- } else {
189
- left = mid + 1
178
+ var left, right int
179
+ for _, w := range weights {
180
+ if left < w {
181
+ left = w
190
182
}
183
+ right += w
191
184
}
192
- return left
185
+ return left + sort.Search(right, func(mx int) bool {
186
+ mx += left
187
+ ws, cnt := 0, 1
188
+ for _, w := range weights {
189
+ ws += w
190
+ if ws > mx {
191
+ ws = w
192
+ cnt++
193
+ }
194
+ }
195
+ return cnt <= days
196
+ })
193
197
}
198
+ ```
194
199
195
- func check (weights []int , days , capacity int ) bool {
196
- cnt , t := 1 , 0
197
- for _ , w := range weights {
198
- if w > capacity {
199
- return false
200
- }
201
- if t+w <= capacity {
202
- t += w
203
- } else {
204
- cnt++
205
- t = w
206
- }
207
- }
208
- return cnt <= days
200
+ ### ** TypeScript**
201
+
202
+ ``` ts
203
+ function shipWithinDays(weights : number [], days : number ): number {
204
+ let left = 0 ;
205
+ let right = 0 ;
206
+ for (const w of weights ) {
207
+ left = Math .max (left , w );
208
+ right += w ;
209
+ }
210
+ const check = (mx : number ) => {
211
+ let ws = 0 ;
212
+ let cnt = 1 ;
213
+ for (const w of weights ) {
214
+ ws += w ;
215
+ if (ws > mx ) {
216
+ ws = w ;
217
+ ++ cnt ;
218
+ }
219
+ }
220
+ return cnt <= days ;
221
+ };
222
+ while (left < right ) {
223
+ const mid = (left + right ) >> 1 ;
224
+ if (check (mid )) {
225
+ right = mid ;
226
+ } else {
227
+ left = mid + 1 ;
228
+ }
229
+ }
230
+ return left ;
209
231
}
210
232
```
211
233
0 commit comments