LeetCode(LCP 74. 最强祝福力场)

本文介绍了如何使用差分数组技术来高效处理二维力场中区域强度的变化,通过`fieldOfGreatestBlessing`方法计算并返回力场强度最大区域的最大值。算法利用优先队列和哈希图进行坐标管理和更新,通过`addRegion`、`addX`、`addY`和`build`函数实现数据结构的更新和计算。
摘要由CSDN通过智能技术生成

题目

在这里插入图片描述

差分数组(Difference Array)

差分数组是一种用于高效处理对原数组某个区间内所有元素进行同一操作(如增加或减少同一个值)的技术。在二维情况下,差分数组可以用于记录二维区域内部的变化,如本例中的力场强度变化。通过在差分数组的特定位置加上或减去值,可以实现对原数组(即实际的力场分布图)的快速更新。具体操作如下:

  • 增加操作:对于一个左上角为 (a, b),右下角为 (c, d) 的矩形区域,其在差分数组 diff 中的操作为:diff[a][b]++diff[a][d+1]--diff[c+1][b]--diff[c+1][d+1]++。这些操作保证了当差分数组还原到原数组时,只有 (a, b)(c, d) 区域内的值增加了。

  • 计算原数组值:通过对差分数组进行前缀和操作(累加从起点到当前点的所有变化量),可以还原出每个位置的实际值。

fieldOfGreatestBlessing(int[][] forceField)

这是主方法,用于计算并返回力场强度最大区域的最大值。

  1. 优先队列和哈希图初始化:创建两个优先队列 pxpy,分别用于存储力场中心点 X 坐标和 Y 坐标的变化值,以及两个哈希图 mapXmapY 用于记录坐标到索引的映射。

  2. 处理力场中心点:遍历每个力场,对于每个力场的 X 和 Y 坐标,分别计算它们加上半径和减去半径的值(左移操作用于防止坐标溢出),并通过 addXaddY 方法更新 mapXmapYpxpy

  3. 建立坐标到索引的映射:将 pxpy 中的元素分别轮询,并使用递增的索引值更新 mapXmapY,为接下来的差分数组计算做准备。

  4. 初始化差分数组:根据 mapXmapY 的大小初始化一个差分数组 diff,这个数组用于记录每个坐标点的力场变化量。

  5. 更新差分数组:遍历每个力场,调用 addRegion 方法更新差分数组,记录力场覆盖区域内每一点的力场增加值。

  6. 计算最大力场值:调用 build 方法处理差分数组,计算每个点的实际力场值,并找到最大的力场值作为结果返回。

addRegion(int[][] diff, int a, int b, int c, int d)

这个方法用于在差分数组 diff 中记录一个力场覆盖区域。通过增加左上角和减少右下角的对角线之外的区域,以达到增加内部区域的目的。

addXaddY

这两个方法负责更新 mapXmapYpxpy,为新的坐标值创建映射并加入到优先队列中,如果这个坐标值之前没有被处理过的话。

build(int[][] diff)

这个方法处理差分数组 diff,通过累加左上角到当前点的变化量,计算出每个点的实际力场值,并找到并返回最大的力场值。

代码

class Solution {
    // 计算力场强度最大区域的最大力场值
    public int fieldOfGreatestBlessing(int[][] forceField) {
        // 用于存储X坐标变化点,按自然顺序排列
        PriorityQueue<Long> px = new PriorityQueue<>();
        // 用于存储Y坐标变化点,按逆自然顺序排列
        PriorityQueue<Long> py = new PriorityQueue<>((a, b) -> b.compareTo(a));
        // 存储X坐标到索引的映射
        HashMap<Long, Integer> mapX = new HashMap<>();
        // 存储Y坐标到索引的映射
        HashMap<Long, Integer> mapY = new HashMap<>();
        
        // 遍历每个力场
        for (int[] f : forceField) {
            long r = f[2];
            // 处理X坐标
            addX(mapX, px, ((long)f[0] << 1) + r);
            addX(mapX, px, ((long)f[0] << 1) - r);
            // 处理Y坐标
            addY(mapY, py, ((long)f[1] << 1) + r);
            addY(mapY, py, ((long)f[1] << 1) - r);
        }
        
        // 建立X坐标到索引的映射
        int index = 1;
        while (!px.isEmpty()) {
            mapX.put(px.poll(), index++);
        }
        // 建立Y坐标到索引的映射
        index = 1;
        while (!py.isEmpty()) {
            mapY.put(py.poll(), index++);
        }
        
        // 初始化差分数组
        int sizeX = mapX.size();
        int sizeY = mapY.size();
        int[][] diff = new int[sizeY + 2][sizeX + 2];
        
        // 更新差分数组
        for (int[] f : forceField) {
            long r = f[2];
            addRegion(diff, mapY.get((long)((f[1] << 1) + r)), mapX.get((long)((f[0] << 1) - r)), mapY.get((long)((f[1] << 1) - r)), mapX.get((long)((f[0] << 1) + r)));
        }
        
        // 计算最大力场值
        return build(diff);
    }

    // 更新差分数组以记录力场影响区域
    public void addRegion(int[][] diff, int a, int b, int c, int d) {
        diff[a][b]++;
        diff[a][d + 1]--;
        diff[c + 1][b]--;
        diff[c + 1][d + 1]++;
    }

    // 添加X坐标变化点
    public void addX(HashMap<Long, Integer> mapX, PriorityQueue<Long> px, Long x) {
        if (!mapX.containsKey(x)) {
            mapX.put(x, -1);
            px.add(x);
        }
    }

    // 添加Y坐标变化点
    public void addY(HashMap<Long, Integer> mapY, PriorityQueue<Long> py, Long y) {
        if (!mapY.containsKey(y)) {
            mapY.put(y, -1);
            py.add(y);
        }
    }

    // 通过处理差分数组来计算并返回力场最大值
    public int build(int[][] diff) {
        int ans = 0;
        // 累加前缀和来还原实际力场值
        for (int i = 1; i < diff.length; i++) {
            for (int j = 1; j < diff[0].length; j++) {
                diff[i][j] += diff[i - 1][j] + diff[i][j - 1] - diff[i - 1][j - 1];
                ans = Math.max(ans, diff[i][j]); // 更新最大力场值
            }
        }
        return ans;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值