当前位置: 首页 > news >正文

Kimi LeetCode 3454. 分割正方形 II C++实现

这是 LeetCode 3454. 分割正方形 II 的 C++ 实现,基于扫描线 + 线段树算法。

核心思路

题目要求找到一条水平线 `y = k`,使得该线以上和以下的正方形并集面积相等。由于正方形可能重叠,需要使用扫描线算法:

1. 离散化 x 坐标:收集所有正方形的左右边界 x 值
2. 扫描线事件:每个正方形产生两个事件——下边界(加入,k=1)和上边界(移除,k=-1)
3. 线段树维护覆盖长度:在 y 轴上扫描时,用线段树维护当前 y 层被覆盖的 x 轴总长度(去重后的并集长度)
4. 两次扫描:第一次计算总面积,第二次找到面积恰好为一半时的 y 坐标

复杂度

- 时间复杂度:O(n log n),其中 n 为正方形数量
- 空间复杂度:O(n)

C++ 代码

```cpp
class Solution {
public:
double separateSquares(vector<vector<int>>& squares) {
unordered_set<long long> xs_set;
vector<tuple<int, long long, long long, int>> events;

for (auto& sq : squares) {
long long x = sq[0], y = sq[1], l = sq[2];
long long x2 = x + l, y2 = y + l;
xs_set.insert(x);
xs_set.insert(x2);
events.emplace_back(y, x, x2, 1);
events.emplace_back(y2, x, x2, -1);
}

sort(events.begin(), events.end());

vector<long long> xs(xs_set.begin(), xs_set.end());
sort(xs.begin(), xs.end());

int n = xs.size();
// 离散化映射
unordered_map<long long, int> mp;
for (int i = 0; i < n; i++) mp[xs[i]] = i;

// 线段树
struct SegTree {
vector<int> cnt;
vector<long long> len;
vector<long long> xs;

SegTree(vector<long long>& xs) : xs(xs) {
int size = xs.size() * 4;
cnt.resize(size);
len.resize(size);
}

void update(int u, int l, int r, int cl, int cr, int k) {
if (cl > r || cr < l) return;
if (cl <= l && r <= cr) {
cnt[u] += k;
} else {
int mid = (l + r) >> 1;
update(u << 1, l, mid, cl, cr, k);
update(u << 1 | 1, mid + 1, r, cl, cr, k);
}
if (cnt[u] > 0) {
len[u] = xs[r + 1] - xs[l];
} else if (l == r) {
len[u] = 0;
} else {
len[u] = len[u << 1] + len[u << 1 | 1];
}
}
};

SegTree tree(xs);

double area = 0;
int prev_y = 0;

// 第一次扫描:计算总面积
for (auto& [y, x1, x2, k] : events) {
area += (double)(y - prev_y) * tree.len[1];
int l = mp[x1], r = mp[x2];
if (l < r) tree.update(1, 0, n - 2, l, r - 1, k);
prev_y = y;
}

double target = area / 2.0;
area = 0;
prev_y = 0;

// 重建线段树,第二次扫描
SegTree tree2(xs);

for (auto& [y, x1, x2, k] : events) {
double cur_len = tree2.len[1];
double t = (double)(y - prev_y) * cur_len;
if (area + t >= target) {
return (double)prev_y + (target - area) / cur_len;
}
area += t;
int l = mp[x1], r = mp[x2];
if (l < r) tree2.update(1, 0, n - 2, l, r - 1, k);
prev_y = y;
}

return 0.0;
}
};
```

关键细节

- 线段树区间表示:`xs` 存储离散化后的 x 坐标,`len[u]` 管理区间 `[xs[l], xs[r+1])`。`update` 中的 `pushup` 逻辑:若 `cnt[u] > 0`,则该区间被完全覆盖,长度为 `xs[r+1] - xs[l]`;否则合并子节点
- 区间更新:对于正方形 `[x1, x2)`,在线段树中更新索引范围 `[l, r-1]`(因为 `xs` 存储的是区间端点,线段树叶子节点对应相邻端点之间的区间)
- 两次扫描:第一次求总面积 `area`,第二次在扫描过程中累加面积,当累加值达到 `area/2` 时,用线性插值计算精确的 y 坐标

下载文件:

http://www.jsqmd.com/news/1119324/

相关文章:

  • Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题
  • Milvus、Qdrant、Chroma:向量数据库选型的工程决策
  • 小白也能看懂的大模型应用架构与Agent:让AI从“只会说“变成“会干活“
  • C# ConditionalAttribute 条件特性+Obsolete 废弃特性
  • stm32四轴飞行器BUG篇
  • 终极DLSS切换秘籍:3步解锁游戏性能新境界
  • CentOS8.0编译源码安装nginx和防火墙使用
  • 政企汇报宣传片为什么离不开 3D 动画?
  • PCB设计中孤铜现象的影响与AD18处理技巧
  • 奇门取号报“订单号不一致”?一次 trade_order_list 的排查实录
  • 《唤醒你的AI同事:WorkBuddy从零上手》034:提示词编写技巧
  • YOLO11全任务适配指南:检测、分割、姿态估计的性能调优技巧
  • 48. OrCAD在创建封装库时,管脚数目很多的元器件应该怎么合理?I Cadence Allegro 电子设计 快问快答
  • 设备单元级(L1)实施路径
  • 批量压缩图片还在用在线工具?这款648KB小软件,画质不变体积暴减
  • 不用喂食不用换水的“水族箱”、逆向净水器的智能水龙头,接入 Home Assistant、用 RF 破解把吊扇接入智能家居|DF创客周刊(第178期)
  • 星火X1 0725 vs 豆包:办公场景下AI模型精准能力实测
  • 混凝土裂隙数据集 建筑物裂缝分割数据集 1000张yolo数据集
  • 【AI编程代码审查黄金标准】:20年资深架构师亲授5大质量保障铁律,错过再等十年?
  • JMeter分布式压测实战:突破单机瓶颈,模拟海量并发
  • 高速PMSM无感控制三大难题与工程解决方案
  • ShadingModel与Lighting
  • ClaudeAPI 医疗场景落地指南:适用边界、提示词与审核流程
  • C++语言基础1:作用域解析运算符“::”详细讲解
  • Scrum落地避坑指南:一个技术负责人踩过的5个流程管理深坑与解法
  • 云服务器已进入黑暗森林时代
  • 【Linux网络】深入 HTTP 协议(一):从初识到 URL 编解码底层探索
  • 【AVRCP】规范精讲[38]:本地调节音量,控制器如何同步感知与更新
  • 演唱会、音乐会适合用的Tally灯
  • DLSS Swapper终极指南:如何智能切换DLSS版本提升游戏帧率