这是我参与8月更文挑战的第26天,活动详情查看:8月更文挑战
leetcode-881-救生艇
[博客链接]
[题目描述]
第 i 个人的体重为 people[i],每艘船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
返回载到每一个人所需的最小船数。(保证每个人都能被船载)。
示例 1:
输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)
示例 2:
输入:people = [3,2,2,1], limit = 3
输出:3
解释:3 艘船分别载 (1, 2), (2) 和 (3)
示例 3:
输入:people = [3,5,3,4], limit = 5
输出:4
解释:4 艘船分别载 (3), (3), (4), (5)
提示:
- 1 <= people.length <= 50000
- 1 <= people[i] <= limit <= 30000
Related Topics
- 贪心
- 数组
- 双指针
- 排序
- 👍 125 👎 0
[题目链接]
[github地址]
[思路介绍]
思路一:贪心+大根堆
- 通过大根堆排序,从最大开始扫描
- 放入船中 如果超过limit 直接res+=1
- 不超过放入第二大的(不满足则一直往下遍历到能满足小于等于limit的元素)
- 然后存储一个栈或者队列存放不满足条件的元素重新放入大根堆
- TLE(70/78)贪心算法想复杂了
public int numRescueBoats(int[] people, int limit) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int person : people
) {
priorityQueue.add(person);
}
Stack<Integer> stack = new Stack<>();
int res = 0;
while (!priorityQueue.isEmpty()) {
int temp = priorityQueue.poll();
if (temp >= limit) {
res += 1;
continue;
}
while (!priorityQueue.isEmpty() && temp + priorityQueue.peek() > limit) {
int value = priorityQueue.poll();
stack.add(value);
}
if (!priorityQueue.isEmpty()) {
priorityQueue.poll();
}
res += 1;
while (!stack.isEmpty()) {
priorityQueue.add(stack.pop());
}
}
return res;
}
- 时间复杂度
- 空间复杂度
思路二:贪心+链表
- 排序不用大根堆
- 思路差不多
- 也TLE了(75/78)
public int numRescueBoats(int[] people, int limit) {
Arrays.sort(people);
int res = 0;
boolean[] vis = new boolean[people.length];
for (int i = people.length - 1; i >= 0; i--) {
if (vis[i]) {
continue;
}
vis[i] = true;
if (people[i] >= limit) {
res++;
continue;
}
int des = limit - people[i];
int j = i - 1;
while (j >= 0) {
if (people[j] <= des && !vis[j]) {
vis[j] = true;
break;
}
j--;
}
res++;
}
return res;
}
- 时间复杂度
- 空间复杂度
思路三:贪心+二分
- 主要就是贪心的逻辑想复杂了,二分查找元素过了
List<Integer> unVis = new ArrayList<>();
public int numRescueBoats(int[] people, int limit) {
Arrays.sort(people);
int res = 0;
for (int i : people
) {
unVis.add(i);
}
while (!unVis.isEmpty()) {
int i = unVis.size() - 1;
if (unVis.get(i) >= limit) {
res++;
unVis.remove(i);
continue;
}
findAndRmJ(i, limit - unVis.get(i));
unVis.remove(unVis.size() - 1);
res++;
}
return res;
}
public void findAndRmJ(int i, int des) {
if (i <= 0) {
return;
}
int l = 0, r = i - 1;
while (l < r) {
int mid = (l - r + 1) / 2 + r;
if (unVis.get(mid) <= des) {
l = mid;
} else {
r = mid - 1;
}
}
if (unVis.get(r) <= des) unVis.remove(r);
}
- 时间复杂度
- 空间复杂度
思路四:贪心算法的优化
- 我好像想复杂了,每次取最轻和最重即可,没必要二分查找满足条件的最大补充元素
public int numRescueBoats(int[] people, int limit) {
Arrays.sort(people);
int l = 0, r = people.length - 1, res = 0;
while (l < r) {
if (people[r] >= limit || people[l] + people[r] > limit) {
r--;
res++;
} else {
r--;
l++;
res++;
}
}
if (l ==r){
res++;
}
return res;
}
- 时间复杂度
- 空间复杂度