# 解题分享:LeetCode 2001. 可互换矩形的组数

解题分享:LeetCode 2001. 可互换矩形的组数

问题描述

题目 2001. 可互换矩形的组数

给定一个下标从 0 开始的二维整数数组 rectangles,其中 rectangles[i] = [width_i, height_i] 表示第 i 个矩形的宽度和高度。

如果两个矩形 iji < j)的宽高比相同,即满足 width_i / height_i == width_j / height_j(使用实数除法而非整数除法),则认为这两个矩形是 可互换 的。

请计算并返回 rectangles 中有多少对 可互换 矩形。

示例

示例 1
输入:rectangles = [[4,8],[3,6],[10,20],[15,30]]
输出:6
解释:所有可互换的矩形对为:
- (0,1), (0,2), (0,3)
- (1,2), (1,3)
- (2,3)
总共 6 对。
示例 2
输入:rectangles = [[4,5],[7,8]]
输出:0
解释:不存在可互换的矩形对。

提示

  • n == rectangles.length
  • 1 <= n <= 10^5
  • rectangles[i].length == 2
  • 1 <= width_i, height_i <= 10^5

解题思路

为了高效地解决这个问题,我们需要找到具有相同宽高比的矩形对。具体来说,如果有 n 个矩形具有相同的宽高比,那么这些矩形之间可以形成 C(n, 2) = n * (n - 1) / 2 对可互换的矩形。

因此,我们的主要任务是:

  1. 计算每个矩形的宽高比。
  2. 统计每种宽高比出现的次数。
  3. 对于每种宽高比,计算对应的组合数 C(n, 2) 并累加。

为了避免浮点数精度问题,我们可以使用最简分数来表示宽高比,即将宽和高除以它们的最大公约数(GCD),然后用一个元组 (width // gcd, height // gcd) 作为键。

代码实现

以下是解决该问题的 Python 代码:

python 复制代码
from collections import defaultdict
from math import gcd
from typing import List

class Solution:
    def interchangeableRectangles(self, rectangles: List[List[int]]) -> int:
        ans = 0
        d = defaultdict(int)
        
        for width, height in rectangles:
            g = gcd(width, height)
            ratio = (width // g, height // g)
            d[ratio] += 1
        
        for count in d.values():
            if count > 1:
                ans += count * (count - 1) // 2
        
        return ans

代码详解

  1. 导入必要的模块

    python 复制代码
    from collections import defaultdict
    from math import gcd
    from typing import List
    • defaultdict 用于创建一个默认值为整数的字典,以便统计每种宽高比出现的次数。
    • gcd 用于计算两个数的最大公约数,以简化宽高比。
    • List 用于类型提示,表明输入 rectangles 是一个列表的列表。
  2. 定义 interchangeableRectangles 方法

    python 复制代码
    class Solution:
        def interchangeableRectangles(self, rectangles: List[List[int]]) -> int:
    • 这是一个类 Solution 中的方法,接受一个二维列表 rectangles,返回一个整数。
  3. 初始化变量

    python 复制代码
    ans = 0
    d = defaultdict(int)
    • ans 用于存储最终的可互换矩形对数。
    • d 是一个 defaultdict,用于记录每种简化后的宽高比出现的次数。
  4. 遍历所有矩形,计算简化后的宽高比并统计

    python 复制代码
    for width, height in rectangles:
        g = gcd(width, height)
        ratio = (width // g, height // g)
        d[ratio] += 1
    • 对于每个矩形,计算其宽和高的最大公约数 g,然后将宽和高分别除以 g,得到简化后的宽高比 ratio
    • 使用这个简化后的比例作为键,在字典 d 中统计其出现的次数。
  5. 计算所有可互换矩形对数

    python 复制代码
    for count in d.values():
        if count > 1:
            ans += count * (count - 1) // 2
    • 遍历字典 d 中所有的值 count,即每种宽高比出现的次数。
    • 对于每种宽高比,如果出现次数大于 1,则可以形成 C(count, 2) = count * (count - 1) // 2 对可互换的矩形。
    • 将每种宽高比对应的组合数累加到 ans 中。
  6. 返回结果

    python 复制代码
    return ans
    • 最后,返回累加得到的可互换矩形对数。

为什么选择简化后的宽高比

使用简化后的宽高比 (width // gcd, height // gcd) 而不是直接使用浮点数 width / height 作为键,有以下几个好处:

  1. 避免浮点数精度问题:浮点数在计算机中表示时可能会有精度误差,导致相同的比例被认为是不同的键。而使用整数对作为键,可以确保比例相同的矩形被归为同一组。

  2. 提高查找效率:整数对在字典中作为键时,比浮点数更具确定性和一致性,有助于提高查找效率。

时间复杂度分析

  • 计算简化后的宽高比 :遍历所有 n 个矩形,每个矩形需要计算 GCD,时间复杂度为 O(log(min(width, height)))。在最坏情况下,总时间复杂度为 O(n log M),其中 M 是矩形中宽或高的最大值。

  • 统计组合数 :遍历字典 d 中的所有键,假设有 k 种不同的宽高比,则时间复杂度为 O(k)。在最坏情况下,k 可以达到 n,即所有矩形的宽高比都不同,此时总时间复杂度为 O(n log M)

  • 总体时间复杂度O(n log M)

优化建议

尽管上述方法已经相当高效,但我们仍可以进行一些优化:

  1. 使用更高效的 GCD 计算:如果语言或环境允许,可以使用更高效的 GCD 算法或内置函数来加速 GCD 的计算。

  2. 减少不必要的操作 :在计算组合数时,只有当 count > 1 时才需要计算 count * (count - 1) // 2,这可以避免不必要的计算。

  3. 使用更高效的数据结构 :在某些语言中,使用特定的数据结构(如 C++ 中的 unordered_map)可能会提供更快的查找和插入速度。

完整代码

以下是最终优化后的完整代码:

python 复制代码
from collections import defaultdict
from math import gcd
from typing import List

class Solution:
    def interchangeableRectangles(self, rectangles: List[List[int]]) -> int:
        ans = 0
        d = defaultdict(int)
        
        for width, height in rectangles:
            g = gcd(width, height)
            ratio = (width // g, height // g)
            d[ratio] += 1
        
        for count in d.values():
            if count > 1:
                ans += count * (count - 1) // 2
        
        return ans

小结

本题通过巧妙地将宽高比简化为最简分数,并利用哈希表统计相同宽高比的矩形数量,进而计算可互换矩形对数。整个过程的时间复杂度为 O(n log M),在题目给定的约束下表现优异。

希望这篇博客能帮助你更好地理解 LeetCode 2001. 可互换矩形的组数 这道题,并掌握解决类似问题的思路和技巧。

参考资料

相关推荐
测试杂货铺25 分钟前
Jmeter随机参数各种搭配
自动化测试·软件测试·python·测试工具·jmeter·职场和发展·测试用例
今天吃饺子1 小时前
小创新模型!6种2024算法优化BiTCN-SVM单变量输入单步预测,MATLAB机器学习预测全家桶再更新...
人工智能·算法·机器学习·支持向量机·matlab
廖显东-ShirDon 讲编程2 小时前
《零基础Go语言算法实战》【题目 2-5】函数参数的值传递和引用传递
算法·程序员·go语言·web编程·go web
不玩return的马可乐2 小时前
LeetCode 747. 至少是其他数字两倍的最大数
数据结构·c++·程序人生·算法·leetcode
bgf_me3 小时前
代码随想录算法训练营第三十二天|509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯
算法
怎么名字都重复3 小时前
1.两数之和--力扣
java·数据结构·算法·leetcode·软件工程
Odaily_3 小时前
SVM赛道概览:MoveVM落地,SVM能走多远
人工智能·算法·机器学习·支持向量机·数据挖掘
深图智能4 小时前
OpenCV的一种改进型的素描特效算法
图像处理·opencv·算法·计算机视觉
Mr.W.T4 小时前
负载均衡原理及算法
算法·负载均衡
KeyPan4 小时前
【机器学习:八、逻辑回归】
人工智能·算法·机器学习·数据挖掘·逻辑回归