提示:
-
1
<
=
d
a
y
s
<
=
w
e
i
g
h
t
s
.
l
e
n
g
t
h
<
=
5
?
1
0
4
1 <= days <= weights.length <= 5 * 10^4
1<=days<=weights.length<=5?104
-
1
<
=
w
e
i
g
h
t
s
[
i
]
<
=
500
1 <= weights[i] <= 500
1<=weights[i]<=500
一开始误以为是“背包问题”,后来看了 三叶姐 题解 才发现原来是 “二分”。
二分
本题和 LeetCode-2226. 每个小孩最多能分到多少糖果 有很大的相似之处。
思路 🤔
-
船所需的最低运载能力:为 max ,即最起码能保证一次能把
w
e
i
g
h
t
s
weights
weights中最大的货物运输到另一港口; -
船所需的最高运载能力:为 sum ,即一次就把全部货物运输到另一港口; -
开始二分
利用“两段性”:设最终所需最小装载能力 res 。若运载能力 < res 时, 则无法满足
d
a
y
s
days
days 天运输完所有货物;若运载能力 >= res 时, 则可以满足
d
a
y
s
days
days 天运输完所有货物
- 当按照运载能力
mid 装船时,可以将所有货物都能在
d
a
y
s
days
days 天内都运输完毕,则“尝试”更小的装载量是否可以满足,即 right = mid - 1 ; - 否则,则说明当前
mid 运载能力不足,则需要船具有更大的运载能力,即 left = mid + 1
class Solution {
public int shipWithinDays(int[] weights, int days) {
int max = 0;
int sum = 0;
for (int weight : weights) {
max = Math.max(max, weight);
sum += weight;
}
int left = max;
int right = sum;
while (left <= right) {
int mid = left + (right - left) / 2;
if (check(weights, mid, days)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
boolean check(int[] weights, int target, int days) {
int cnt = 0;
for (int i = 0; i < weights.length; ) {
int sum = 0;
while (i < weights.length && sum + weights[i] <= target) {
sum += weights[i++];
}
cnt++;
}
return cnt <= days;
}
public static void main(String[] args) {
int[] nums = {1,2,3,4,5,6,7,8,9,10};
int days = 5;
System.out.println(new Solution().shipWithinDays(nums, days));
}
}
二分
class Solution {
public int splitArray(int[] nums, int m) {
int n = nums.length;
int max = 0;
int sum = 0;
for (int i : nums) {
sum += i;
max = Math.max(max, i);
}
int left = max;
int right = sum;
while (left <= right) {
int mid = left + (right - left) / 2;
if (check(nums, mid, m)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
boolean check(int[] nums, int target, int m) {
int cnt = 0;
for (int i = 0; i < nums.length; ) {
int sum = 0;
while (i < nums.length && sum + nums[i] <= target) {
sum += nums[i++];
}
cnt++;
}
return cnt <= m;
}
}
|