LeetCode 每日一题笔记
0. 前言
- 日期:2026.05.31
- 题目:2126. 摧毁小行星
- 难度:中等
- 标签:数组、贪心、排序
1. 题目理解
问题描述 :
给定行星初始质量 mass 和小行星数组 asteroids,可以按任意顺序与小行星碰撞:
- 行星质量 ≥ 小行星质量:行星摧毁小行星,并获得其质量;
- 行星质量 < 小行星质量:行星被摧毁。
判断是否存在一种顺序,让行星摧毁所有小行星。
示例:
输入:mass = 10, asteroids = 3,9,19,5,21
输出:true
解释:按 3,5,9,19,21 的顺序,行星质量依次增长为 13→18→27→46→67,可全部摧毁。
2. 解题思路
核心观察
- 贪心策略:优先摧毁质量小的小行星,才能不断增长行星质量,为后续摧毁更大的小行星创造条件;
- 排序后遍历,只要过程中行星质量始终不小于当前小行星,就能完成全部摧毁。
算法步骤
- 将小行星数组按升序排序;
- 用
long类型记录行星当前质量,避免溢出; - 遍历排序后的数组,若行星质量小于当前小行星,直接返回
false; - 否则累加小行星质量,遍历结束返回
true。
3. 代码实现
java
package lc2126;
import java.util.Arrays;
class Solution {
public boolean asteroidsDestroyed(int mass, int[] asteroids) {
Arrays.sort(asteroids);
long cur = mass;
for (int a : asteroids) {
if (cur < a) return false;
cur += a;
}
return true;
}
}
4. 代码优化说明
(代码未做任何修改,仅添加注释讲解)
java
class Solution {
public boolean asteroidsDestroyed(int mass, int[] asteroids) {
// 找到所有小行星中的最大质量,用于确定二进制分组的最高位
int mx = 0;
for (int x : asteroids) {
mx = Math.max(mx, x);
}
// 计算最大质量的二进制位数,确定分组数量
int maxWidth = 32 - Integer.numberOfLeadingZeros(mx);
// sum数组:存储每个二进制位分组内所有小行星的质量和
long[] sum = new long[maxWidth];
// mn数组:存储每个二进制位分组内的最小小行星质量
int[] mn = new int[maxWidth];
Arrays.fill(mn, Integer.MAX_VALUE);
// 按二进制最高位对小行星进行分组
for (int x : asteroids) {
// 计算当前小行星的最高二进制位
int i = 31 - Integer.numberOfLeadingZeros(x);
sum[i] += x;
mn[i] = Math.min(mn[i], x);
}
// 行星当前质量,用long避免溢出
long m = mass;
// 按二进制位从低到高遍历分组
for (int i = 0; i < maxWidth; i++) {
// 该分组无小行星,跳过
if (mn[i] == Integer.MAX_VALUE) {
continue;
}
// 行星质量小于该分组最小的小行星,无法摧毁,直接返回false
if (m < mn[i]) {
return false;
}
// 摧毁该分组所有小行星,累加质量
m += sum[i];
}
// 所有分组都可摧毁,返回true
return true;
}
}
5. 复杂度分析
- 排序贪心解法
- 时间复杂度:O(nlogn)O(n \log n)O(nlogn),排序占主要开销,遍历为线性。
- 空间复杂度:O(1)O(1)O(1),原地排序(不考虑排序栈开销),仅用常数变量。
- 二进制分组优化解法
- 时间复杂度:O(n)O(n)O(n),两次线性遍历,无排序开销。
- 空间复杂度:O(logM)O(\log M)O(logM),MMM 为最大小行星质量,分组数组大小为常数级。
6. 总结
- 核心:贪心思想,优先处理质量小的目标,是解决此类"增长型"问题的通用策略;
- 排序解法直观易写,面试优先使用;二进制分组解法在大数据下效率更高,可作为进阶优化;
- 关键细节:行星质量累加可能超过
int范围,需用long类型存储,避免溢出错误。