Day4: GG高频面经 | LC2013 Detect Squares|Sundri |哈希表,判断正方形

lc2013 Detect Squares - LeetCode

给你一个在 X-Y 平面上的点构成的数据流。设计一个满足下述要求的算法:

添加 一个在数据流中的新点到某个数据结构中。可以添加 重复 的点,并会视作不同的点进行处理。
给你一个查询点,请你从数据结构中选出三个点,使这三个点和查询点一同构成一个 面积为正 的 轴对齐正方形 ,统计 满足该要求的方案数目。
轴对齐正方形 是一个正方形,除四条边长度相同外,还满足每条边都与 x-轴 或 y-轴 平行或垂直。

实现 DetectSquares 类:

DetectSquares() 使用空数据结构初始化对象
void add(int[] point) 向数据结构添加一个新的点 point = [x, y]
int count(int[] point) 统计按上述方式与点 point = [x, y] 共同构造 轴对齐正方形 的方案数。
 

示例:
输入:
["DetectSquares", "add", "add", "add", "count", "count", "add", "count"]
[[], [[3, 10]], [[11, 2]], [[3, 2]], [[11, 10]], [[14, 8]], [[11, 2]], [[11, 10]]]
输出:
[null, null, null, null, 1, 0, null, 2]

提示:

point.length == 2
0 <= x, y <= 1000
调用 add 和 count 的 总次数 最多为 5000

# 解题思路

1.构造函数:创建一个邻接表,默认值设置为 int

2. add方法:使用哈希表记录下所有点出现的次数:key是坐标,value是该坐标出现的次数

2. count方法:传入一个点名字为 point,坐标为(x,y),问你这个点能够构成多少个正方形。思路其实非常简单:遍历哈希表里面所有已经记录下来的点,每个点暂时记录为 (x1, y1)。如果说point和当前这个点能构成一个正方形,那么一定满足:

1. 两个坐标不是同一个坐标(x != x1, y != y1)

2. 两个坐标之间横纵坐标的绝对值差是相等的:abs(x-x1) == abs(y-y1)

3. 遍历的这个点(x1, y1),其实是 point 对角线上的这个点!因为只有直到对角线上点的坐标,才能够轻易推出剩下两个点的坐标,所以才会有那句 x != x1, y != y1,来排除掉和 point 直接相邻的点!

示意图:

point (x, y )       -----------------------------------  (x1, y) if x == x1, continue

|                                                        |

|                                                        |

                                          (x, y1) ______________________(x1,y1) - 遍历中真正要找的点!

if y == y1, continue

# 解题代码:

class DetectSquares(object):

    def __init__(self):
        self.d = collections.defaultdict(int)

    def add(self, point):
        """
        :type point: List[int]
        :rtype: None
        """
        self.d[tuple(point)] += 1
        

    def count(self, point):
        """
        :type point: List[int]
        :rtype: int
        """
        px,py = point
        res = 0
        for x, y in self.d.keys():
            if (abs(px-x) != abs(py-y)) or px == x or py == y:
                continue
            res += self.d[(x,py)] * self.d[(px,y)]  * self.d[(x,y)]
        return res

# 易错点分析:

1.一开始的边界问题可以问什么?

x和y坐标的范围是什么;point数组的长度是什么,constriant里面的问题就是我应该要在面试过程去和面试官求证的问题。

2. 遍历哈希里面的点的时候,其实是在遍历哪个点?

其实是在寻找对角线上面的那个点,通过对角线那个点推出另外两个坐标为(x,y1), (x1,y),那么就能够凑齐(x,y1), (x1,y),(x,y)这三个点的坐标。找到之后, 就直接去哈希表里面查看,这三个点是否存在,如果存在,就是三个点出现的频率相乘

3. 为什么defaultdict的默认值一定要写int? 

因为不写的话,如果(x,y1), (x1,y),(x,y) 其中任意一个点在dic里面不存在的话,就会报key error的错误。所以默认值写成int是为了避免key error

4. 为什么 for x1, y1 in d.keys() 会报 Dictionary Changed Size During Iteration Python 3 的错?

大概是说字典在遍历时不能进行修改,建议转成列表或集合处理。

例如:list(my_dict.keys()) 和 list(my_dict)的结果都是字典的键的列表

但是我尝试把self.d进行深度拷贝,结果也并没有顺利通过和运行。同样的代码,在python2能够顺利通过,但是在python3就是不能通过的。

# 时空复杂度: 

时间:O(N)构建哈希表所需要的时间

空间:O(N)哈希表存储的元素数量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值