LeetCode 3625. 统计梯形的数目 II

【力扣周赛题解】Count Number of Trapezoids II

📚 本文用最简单的方式,带你理解这道力扣周赛几何题!


📌 什么是梯形?

在开始之前,让我们先回忆一下初中数学:

复制代码
        上底
    ┌─────────┐
   /           \
  /             \
 /               \
└─────────────────┘
        下底

梯形 = 有且只有一对平行边的四边形

但这道题更宽松一点:只要有至少一对平行边就算梯形(包括平行四边形)


🎯 题目说了啥?

简单版本:给你一堆点,从中选 4 个点,看能组成多少个梯形?

复制代码
举个例子:平面上有这些点

    ●A          ●B
    
    
●C                  ●D
    
        ●E      ●F

我们要找出所有能组成梯形的 4 点组合!


🤔 怎么判断两条线平行?

还记得初中学的吗?斜率相同的两条线平行!

复制代码
斜率 = 上升的高度 ÷ 水平移动的距离
     = (y₂ - y₁) ÷ (x₂ - x₁)

看图理解:

复制代码
                    ●B(4,3)
                   /
                  / ↑ 上升2格
                 /  |
        ●A(2,1) ────→
                水平走2格

斜率 = 2 ÷ 2 = 1

如果两条线段的斜率一样,它们就是平行的!

复制代码
        线段1:斜率 = 1
    ●───────●
                    ← 这两条线平行!
        ●───────●
        线段2:斜率 = 1

💡 解题思路(大白话版)

第一步:找出所有的线段

假设有 4 个点 A、B、C、D,那我们可以画出 6 条线段:

复制代码
AB  AC  AD  BC  BD  CD

就像这样:
    A●─────────●B
     |\       /|
     | \     / |
     |  \   /  |
     |   \ /   |
     |    X    |
     |   / \   |
     |  /   \  |
     | /     \ |
     |/       \|
    C●─────────●D

第二步:把斜率相同的线段放一起

就像整理书架一样,把"方向相同"的线段归类:

复制代码
📁 斜率 = 0 的文件夹(水平线)
   ├── 线段 AB(上边)
   └── 线段 CD(下边)

📁 斜率 = ∞ 的文件夹(垂直线)
   ├── 线段 AC(左边)
   └── 线段 BD(右边)

📁 斜率 = -1 的文件夹(↘ 方向)
   └── 线段 AD(左上到右下的对角线)

📁 斜率 = 1 的文件夹(↗ 方向)
   └── 线段 BC(右上到左下的对角线,反过来看就是↗)

第三步:在每个文件夹里找"配对"

同一个文件夹里的线段都是平行的

每选 2 条线段,就可能组成一个梯形的"上底和下底"!

复制代码
从"斜率=0"文件夹里选 AB 和 CD:

    A●───────────●B   ← 上底
     |           |
     |           |
    C●───────────●D   ← 下底
    
    👆 这就是一个梯形(其实是长方形)!

⚠️ 但是!有些情况不能算

情况1:两条线段在同一条直线上 ❌

复制代码
    ●────●────●────●
    A    B    C    D
    
    线段 AB 和 CD 虽然平行,但在同一条线上!
    这样选 4 个点,它们排成一排,组不成四边形!

情况2:两条线段共用一个端点 ❌

复制代码
        ●B
       /
    ●A
       \
        ●C
        
    线段 AB 和 AC 共用了点 A
    这样只有 3 个点,组不成四边形!

情况3:平行四边形会被数两次 ⚠️

复制代码
    ●───────────●
    |           |
    |           |
    ●───────────●
    
    这个图形有两对平行边!
    - 上下两条边平行 → 数了 1 次
    - 左右两条边平行 → 又数了 1 次
    
    所以要减掉重复的!

🧮 完整计算步骤

让我们一步步算出答案:

第 1 步:在每个斜率文件夹里数配对

假设某个文件夹里有 k 条线段,从中选 2 条的方法数是:

复制代码
C(k,2) = k × (k-1) ÷ 2

例如:有 4 条线段,选 2 条 = 4 × 3 ÷ 2 = 6 种选法

第 2 步:减掉不合法的情况

复制代码
❌ 减掉「共线」的配对
   (两条线段在同一条直线上)

❌ 减掉「共端点」的配对  
   (两条线段共用一个点)

✅ 但是!如果既共线又共端点,被减了两次,要加回来一次

第 3 步:减掉平行四边形的重复计数

复制代码
平行四边形有 2 对平行边,被数了 2 次
所以最后要 - 平行四边形数量

📐 最终公式

复制代码
┌────────────────────────────────────────────────────────────────┐
│                                                                │
│  对于每个斜率文件夹:                                            │
│                                                                │
│    有效配对数 = C(k,2)                                          │
│               - 共线的配对数                                    │
│               - 共端点的配对数                                   │
│               + 既共线又共端点的配对数(加回来)                   │
│                                                                │
│  ─────────────────────────────────────────────                 │
│                                                                │
│  答案 = 所有文件夹的有效配对数之和 - 平行四边形数量               │
│                                                                │
└────────────────────────────────────────────────────────────────┘

💡 这个"减了又加回来"的技巧叫做容斥原理,是组合数学中常用的方法!


🎨 完整例子

假设有 5 个点:

复制代码
    ●(0,2)              ●(4,2)
    
    
    ●(0,0)    ●(2,0)    ●(4,0)

Step 1: 找所有线段并分类

线段 斜率
(0,0)-(4,0) 0(水平)
(0,0)-(2,0) 0(水平)
(2,0)-(4,0) 0(水平)
(0,2)-(4,2) 0(水平)
(0,0)-(0,2) ∞(垂直)
(4,0)-(4,2) ∞(垂直)
... ...

Step 2: 在"水平线"文件夹里找配对

排除掉在同一条直线上的(比如下面那 3 条线段都在 y=0 这条线上)

有效配对:上面那条线 + 下面某条线 = 梯形!

Step 3: 数一数,得出答案!


🔑 编程小技巧

怎么避免小数?

斜率可能是 0.333333... 这样的无限小数,计算机算不准!

解决方法:用分数表示斜率!

复制代码
比如斜率 = 2/6

不要算成 0.333...
而是约分成 1/3,存成 (1, 3) 这对数字

怎么判断平行四边形?

平行四边形有个特点:两条对角线的中点重合

复制代码
    A●─────────────●B
      \           /
       \         /
        \       /
         \     /
          \   /
           \ /
            ● ← 对角线 AD 和 BC 在此相交,中点重合!
           / \
          /   \
         /     \
        /       \
       /         \
    C●─────────────●D

换一种方式理解:

复制代码
对角线 AD 的中点 = ( (Ax+Dx)/2, (Ay+Dy)/2 )
对角线 BC 的中点 = ( (Bx+Cx)/2, (By+Cy)/2 )

如果这两个中点相同 → 这 4 个点组成平行四边形!

所以我们只要:

  1. 算出每对点的中点
  2. 如果有两对点中点相同,它们就能组成平行四边形!

⏱️ 这个方法快吗?

点的数量 大约要算多少次
10 个点 100 次
100 个点 10,000 次
500 个点 250,000 次

对计算机来说,25 万次计算简直是小菜一碟!✅


📝 总结

复制代码
解题三步走:

    ┌──────────────┐
    │ 1️⃣ 枚举线段    │
    │   找出所有两点 │
    │   组成的线段   │
    └──────┬───────┘
           ↓
    ┌──────────────┐
    │ 2️⃣ 按斜率分组  │
    │   斜率相同的   │
    │   放一起      │
    └──────┬───────┘
           ↓
    ┌──────────────┐
    │ 3️⃣ 配对计数    │
    │   排除不合法的 │
    │   减去重复的   │
    └──────────────┘

🎉 恭喜你看完了!

这道题结合了:

  • 📐 几何知识:斜率、平行、中点
  • 🧠 算法思维:分类、配对、去重
  • 💻 编程技巧:避免小数、用哈希表分组

是不是没有想象中那么难呢?😄


💬 如果觉得有帮助,欢迎点赞收藏!有问题可以在评论区讨论~

相关推荐
橘颂TA39 分钟前
【剑斩OFFER】算法的暴力美学——外观数列
算法·leetcode·职场和发展·结构与算法
Liangwei Lin40 分钟前
洛谷 P1434 [SHOI2002] 滑雪
算法
c#上位机1 小时前
halcon图像增强之自动灰度拉伸
图像处理·算法·c#·halcon·图像增强
rit84324991 小时前
压缩感知信号恢复算法:OMP与CoSaMP对比分析
数据库·人工智能·算法
Pluchon2 小时前
硅基计划4.0 算法 FloodFill算法
java·算法·leetcode·决策树·逻辑回归·深度优先·图搜索算法
菜鸟233号2 小时前
力扣347. 前k个高频元素 java实现
算法
Xの哲學3 小时前
Linux设备管理:从内核驱动到用户空间的完整架构解析
linux·服务器·算法·架构·边缘计算
xinyu_Jina3 小时前
Info Flow:去中心化数据流、跨协议标准化与信息源权重算法
算法·去中心化·区块链
Jac_kie_層樓3 小时前
力扣hot100刷题记录(12.2)
算法·leetcode·职场和发展