leetcode 6043 2251树状数组的应用

题目描述6043:
给你一个二维整数数组 rectangles ,其中 rectangles[i] = [li, hi] 表示第 i 个矩形长为 li 高为 hi 。给你一个二维整数数组 points ,其中 points[j] = [xj, yj] 是坐标为 (xj, yj) 的一个点。

第 i 个矩形的 左下角 在 (0, 0) 处,右上角 在 (li, hi) 。

请你返回一个整数数组 count ,长度为 points.length,其中 count[j]是 包含 第 j 个点的矩形数目。

如果 0 <= xj <= li 且 0 <= yj <= hi ,那么我们说第 i 个矩形包含第 j 个点。如果一个点刚好在矩形的 边上 ,这个点也被视为被矩形包含。
示例1:
在这里插入图片描述
输入:rectangles = [[1,2],[2,3],[2,5]], points = [[2,1],[1,4]]
输出:[2,1]
解释:
第一个矩形不包含任何点。
第二个矩形只包含一个点 (2, 1) 。
第三个矩形包含点 (2, 1) 和 (1, 4) 。
包含点 (2, 1) 的矩形数目为 2 。
包含点 (1, 4) 的矩形数目为 1 。
所以,我们返回 [2, 1] 。

示例2:
在这里插入图片描述
输入:rectangles = [[1,1],[2,2],[3,3]], points = [[1,3],[1,1]]
输出:[1,3]
解释:
第一个矩形只包含点 (1, 1) 。
第二个矩形只包含点 (1, 1) 。
第三个矩形包含点 (1, 3) 和 (1, 1) 。
包含点 (1, 3) 的矩形数目为 1 。
包含点 (1, 1) 的矩形数目为 3 。
所以,我们返回 [1, 3] 。
思路:
本题如果暴力求解的话会超出时间限制,所以提出了使用有序list:Sortedlist和树状数组的方式。

from typing import List
from sortedcontainers import SortedList

class Solution:
    def countRectangles(self, rectangles: List[List[int]], points: List[List[int]]) -> List[int]:

        rectangles.sort(reverse=True)  # 按照横、纵坐标倒序排列
        points = [(x, y, i) for i, (x, y) in enumerate(points)]
        points.sort(reverse=True)  # points 也是倒序排列的这样可以减少比较的时间

        n = len(rectangles)
        res = [0] * len(points)


        j = 0  # 指向rectangles
        sl = SortedList()  # 有序数组:存储rec_y: rectangles[1]
        for x, y, i in points:
            # 【固定x,二分搜索y】
            # 每次循环的时候,不需要对j进行重新赋值,因为points和rec都是降序排列完毕的
            print("当前的i, j:", i, j)
            while j < n and x <= rectangles[j][0]:  # rec_x >= point_x的矩形,其rec_y入列
                sl.add(rectangles[j][1])  # 有序数组sl中加入新元素rec_y
                j += 1
            print(sl)
            print("含义:",sl.bisect_left(y))
            res[i] = len(sl) - sl.bisect_left(y)  # 每次只需要考虑y满足的有几个即可
            # sl.bisect_left(y):表示当前有序数组sl中纵坐标 rec_y 比 point_y 小的矩形数目
            # 这个函数是一个二分查找的形式,也可以减少时间复杂度
        return res

from typing import List
# 树状数组就是求区间和的一种方式
# 本题的思想就是在固定x之后,找满足的y的区间范围内[y, max_y]之间的数量
# 这个数量对应的就是一个数组的区间和(可以用区间和的差值得到)
# 树状数组的一个较大的应用就是前缀和
# 这种利用树状数组求前缀和的方式,在原数组发生改变的时候,求前缀和的时间复杂度会减少,因为是分区间进行求解的

class Solution:
    def countRectangles(self, rectangles: List[List[int]], points: List[List[int]]) -> List[int]:

        '''树状数组模板'''   # 这里需要背下来

        def lowbit(x):  # lowbit函数
            return x & (-x)

        def add(i, delta):  # 坐标i处依次添加delta
            while i < len(tree):
                tree[i] += delta
                i += lowbit(i)

        def query(i):  # presum函数
            presum = 0
            while i > 0:
                presum += tree[i]
                i -= lowbit(i)
            return presum

        '''主程序'''
        rectangles.sort(reverse=True)  # 按照横、纵坐标倒序排列
        points = [(x, y, i) for i, (x, y) in enumerate(points)]
        points.sort(reverse=True)

        # 【固定x,检索y】
        max_recy = 0  # 树状数组中元素的最大值
        for rec in rectangles:
            max_recy = max(max_recy, rec[1])   # 求y的最大值
        print(max_recy)
        tree = [0] * (max_recy + 1)  # 树状数组的大小,这里需要注意加一,因为树状数组是从1开始的
        print(tree)
        res = [0] * len(points)
        j = 0
        for (x, y, i) in points:
            if y > max_recy:  # point_y > rec_y的最大值,没有矩形能够包含
                continue
            # rec_x >= point_x的矩形,其rec_y放入树状数组中
            while j < len(rectangles) and x <= rectangles[j][0]:
                add(rectangles[j][1], 1)  # 更新树状数组 注意这里树状数组的含义:“+1”部分,思想比较巧妙
                j += 1
            print("当前i下,树状数组为:", i, tree)

            res[i] = query(max_recy) - query(y - 1)  # 区间和

        return res

2251和本题是完全类似的,只是从二维变成了一维
问题链接

# 相当于和6043相同的,只不过是把比较的数组变成了一维的
# 相当于横坐坐标都是相同的值
# 用排序和树状数组都可以解
from sortedcontainers import SortedList
class Solution(object):
    def fullBloomFlowers(self, flowers, persons):
        """
        :type flowers: List[List[int]]
        :type persons: List[int]
        :rtype: List[int]
        """
        flowers.sort()  # 倒序排列
        persons = [(x, i) for i, x in enumerate(persons)]
        persons.sort()

        n = len(flowers)
        j = 0
        res = [0] * len(persons)
        sl = SortedList()
        for x, i in persons:
            while j < n and x >= flowers[j][0]:
                sl.add(flowers[j][1])
                j += 1
            res[i] = len(sl) - sl.bisect_left(x)
        return res

# 利用树状数组进行求解

class Solution(object):
    def fullBloomFlowers(self, flowers, persons):
        """
        :type flowers: List[List[int]]
        :type persons: List[int]
        :rtype: List[int]
        """
        flowers.sort()
        persons = [(x,i) for i,x in enumerate(persons)]
        persons.sort()

        # 树状数组模板
        def lowbit(x):
            return x & (-x)

        def add(i, delta): # 在i处加delta
            while i < len(tree):
                tree[i] += delta
                i += lowbit(i)

        def query(i): # 前缀和函数
            preum = 0
            while i > 0:
                # print(i)
                preum += tree[i]
                i -= lowbit(i)
            return preum

        n = len(flowers)
        j = 0
        max_f = 0  # 树状数组中元素的最大值
        for rec in flowers:
            max_f = max(max_f, rec[1])  # 求y的最大值
        # print("最大值:", max_f)
        tree = [0] * (max_f+1)   # !!!这种方式维护一个tree使用的内存太多了
        res = [0] * len(persons)

        for x, i in persons:
            if x > max_f:
                continue
            while j < n and x >= flowers[j][0]:
                add(flowers[j][1], 1)
                j += 1
            res[i] = query(max_f) - query(x-1)
        return res

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值