LeetCode 3623. 统计梯形的数目 I

题目描述

给你一个二维整数数组 points,其中 points[i] = [xi, yi] 表示第 i 个点在笛卡尔平面上的坐标。

水平梯形 是一种凸四边形,具有 至少一对 水平边(即平行于 x 轴的边)。

返回可以从 points 中任意选择四个不同点组成的 水平梯形 数量,结果对 10^9 + 7 取模。


解题思路

核心观察

这道题的关键在于理解"水平边"的含义:

水平边 = 两个 y 坐标相同的点连成的线段

因此,我们可以把问题转化为:

  1. 按 y 坐标对所有点进行分组
  2. 每个分组内的点都在同一条水平线上
  3. 从两条不同的水平线上各选 2 个点,就能组成一个水平梯形

组合计数

设某条水平线(y = k)上有 cnt 个点,那么从中选 2 个点作为一条水平边的方案数为:

C(cnt,2)=cnt×(cnt−1)2C(cnt, 2) = \frac{cnt \times (cnt - 1)}{2}C(cnt,2)=2cnt×(cnt−1)

假设我们有多条水平线,每条线上能产生的"边对数"分别为 a1,a2,...,ama_1, a_2, \ldots, a_ma1,a2,...,am。

从两条不同的水平线上各取一条边来组成梯形,总方案数为:

ans=∑i<jai×aj\text{ans} = \sum_{i < j} a_i \times a_jans=i<j∑ai×aj

优化计算

直接双重循环计算会是 O(m2)O(m^2)O(m2),但我们可以用累加技巧在 O(m)O(m)O(m) 内完成:

复制代码
sum = 0, ans = 0
for each ai:
    ans += ai * sum
    sum += ai

这样每次用当前的 ai 乘以之前所有 aj 的累加和,避免了重复计算。


复杂度分析

维度 复杂度
时间 O(n)O(n)O(n),其中 n 为点的数量
空间 O(m)O(m)O(m),其中 m 为不同 y 值的数量

注意事项

  1. 溢出风险C(cnt, 2) 最大可达 105×1052≈5×109\frac{10^5 \times 10^5}{2} \approx 5 \times 10^92105×105≈5×109,乘法时需要使用 int64 并及时取模
  2. 跳过无效行 :如果某行只有 1 个点,C(1, 2) = 0,可以直接跳过
  3. 取模运算 :每次乘法和加法后都要对 10^9 + 7 取模

Go 代码实现

go 复制代码
package main

const MOD = 1_000_000_007

func countTrapezoids(points [][]int) int {
    // 按 y 坐标分组,统计每个 y 值出现的次数
    yCount := make(map[int]int)
    for _, p := range points {
        yCount[p[1]]++
    }

    // 计算每条水平线上的边对数 C(cnt, 2)
    // 然后用累加技巧计算所有不同行的组合
    var sum, ans int64 = 0, 0

    for _, cnt := range yCount {
        if cnt < 2 {
            continue
        }
        // C(cnt, 2) = cnt * (cnt - 1) / 2
        pairs := int64(cnt) * int64(cnt-1) / 2 % MOD
        ans = (ans + pairs*sum) % MOD
        sum = (sum + pairs) % MOD
    }

    return int(ans)
}

示例验证

示例 1

复制代码
输入:points = [[1,0],[2,0],[3,0],[2,2],[3,2]]
输出:3
  • y=0 上有 3 个点 → C(3,2) = 3 条边
  • y=2 上有 2 个点 → C(2,2) = 1 条边
  • 答案 = 3 × 1 = 3 ✓

示例 2

复制代码
输入:points = [[0,0],[1,0],[0,1],[2,1]]
输出:1
  • y=0 上有 2 个点 → C(2,2) = 1 条边
  • y=1 上有 2 个点 → C(2,2) = 1 条边
  • 答案 = 1 × 1 = 1 ✓

总结

这道题本质上是一道 组合计数 问题,核心技巧是:

  1. 按 y 坐标分组
  2. 计算每组的边对数
  3. 用累加优化双重循环

掌握这个思路后,类似的"选点组成特定图形"问题都可以用相似方法解决。

相关推荐
致Great2 小时前
科研人的 AI,不该只回答问题:我用字节TraeWork 跑了一遍真实研究任务
算法
纵有疾風起2 小时前
线性表的定义与基本操作 — 从逻辑结构到 ADT 接口
数据结构·算法·408·线性表·adt
测试_AI_一辰2 小时前
AI Agent 评测最隐蔽的坑-记忆
人工智能·算法·ai·自动化·ai编程
lucas_AI2 小时前
给YOLO检测器插 LoRA,'插对地方'比'插什么'更要命
人工智能·算法
LuminousCPP3 小时前
数据结构-时间与复杂度|时间/空间复杂度 + 两道力扣练习 + 二分查找复盘
c语言·数据结构·经验分享·算法·leetcode
Nil2083 小时前
leetcode 三数之和
数据结构·算法·leetcode
小小龙学IT3 小时前
C++ std::vector 底层实现深度解析:内存布局、扩容策略、移动语义与迭代器失效
开发语言·c++·算法
noipp3 小时前
推荐题目:洛谷 P16689 出征
java·开发语言·数据结构·c++·算法·洛谷·luogu
eBest数字化转型方案4 小时前
从工程视角拆解冰柜资产管理:拍照识别 pipeline、纯净度算法与 IoT 选型踩坑
人工智能·物联网·算法
Interview Aid1124 小时前
Roblox OA 面经|小游戏+编程双修,Coding 两题满分通过
算法