【算法】1476. 子矩形查询(java / c / c++ / python / go / rust)

简介: 请你实现一个类 SubrectangleQueries ,它的构造函数的参数是一个 rows x cols 的矩形(这里用整数矩阵表示),并支持以下两种操作: updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) 用 newValue 更新以 (row1,col1) 为左上角且以 (row2,col2) 为右下角的子矩形。 getValue(int row, int col) 返回矩形中坐标 (row,col) 的当前值。

1476. 子矩形查询:

请你实现一个类 SubrectangleQueries ,它的构造函数的参数是一个 rows x cols 的矩形(这里用整数矩阵表示),并支持以下两种操作:

  1. updateSubrectangle(int row1, int col1, int row2, int col2, int newValue)
  • 用 newValue 更新以 (row1,col1) 为左上角且以 (row2,col2) 为右下角的子矩形。
  1. getValue(int row, int col)
  • 返回矩形中坐标 (row,col) 的当前值。

样例 1


输入:
    
  ["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue","getValue"]
  [[[[1,2,1],[4,3,4],[3,2,1],[1,1,1]]],[0,2],[0,0,3,2,5],[0,2],[3,1],[3,0,3,2,10],[3,1],[0,2]]

输出:

  [null,1,null,5,5,null,10,5]

解释:

  SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,2,1],[4,3,4],[3,2,1],[1,1,1]]);  
  // 初始的 (4x3) 矩形如下:
  // 1 2 1
  // 4 3 4
  // 3 2 1
  // 1 1 1
  subrectangleQueries.getValue(0, 2); // 返回 1
  subrectangleQueries.updateSubrectangle(0, 0, 3, 2, 5);
  // 此次更新后矩形变为:
  // 5 5 5
  // 5 5 5
  // 5 5 5
  // 5 5 5 
  subrectangleQueries.getValue(0, 2); // 返回 5
  subrectangleQueries.getValue(3, 1); // 返回 5
  subrectangleQueries.updateSubrectangle(3, 0, 3, 2, 10);
  // 此次更新后矩形变为:
  // 5   5   5
  // 5   5   5
  // 5   5   5
  // 10  10  10 
  subrectangleQueries.getValue(3, 1); // 返回 10
  subrectangleQueries.getValue(0, 2); // 返回 5
AI 代码解读

样例 2

输入:

  ["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue"]
  [[[[1,1,1],[2,2,2],[3,3,3]]],[0,0],[0,0,2,2,100],[0,0],[2,2],[1,1,2,2,20],[2,2]]

输出:

  [null,1,null,100,100,null,20]

解释:

  SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,1,1],[2,2,2],[3,3,3]]);
  subrectangleQueries.getValue(0, 0); // 返回 1
  subrectangleQueries.updateSubrectangle(0, 0, 2, 2, 100);
  subrectangleQueries.getValue(0, 0); // 返回 100
  subrectangleQueries.getValue(2, 2); // 返回 100
  subrectangleQueries.updateSubrectangle(1, 1, 2, 2, 20);
  subrectangleQueries.getValue(2, 2); // 返回 20
AI 代码解读

提示

  • 最多有 500 次updateSubrectangle 和 getValue 操作。
  • 1 <= rows, cols <= 100
  • rows == rectangle.length
  • cols == rectangle[i].length
  • 0 <= row1 <= row2 < rows
  • 0 <= col1 <= col2 < cols
  • 1 <= newValue, rectanglei <= 109
  • 0 <= row < rows
  • 0 <= col < cols

分析

  • 矩形的初始值肯定要保存下来。
  • 然后最直观的方式就是每次更新操作就把矩形中的值老老实实更新掉,取值就直接返回就可以了。
  • 根据提示,我们可以知道矩形最大是100 * 100,也就是每次更新值最多可能需要更新10000个值,但是更新次数最多会有500次,所以我们可以记录每次更新操作,在取值的时候我们倒着查找历史操作,如果点没有做过更新,那就是原值。这样更新操作的时间复杂度仅仅是O(1),而取值操作最多就是500次循环去查找历史。
  • 到底哪种方式好不是绝对的,可以根据实际情况,本题的情况是值多,操作少,所以我们不做更新,而是把历史操作存下来。

题解

java

class SubrectangleQueries {
    private final int[][]     rectangle;
    private       List<int[]> history = new ArrayList<>();

    public SubrectangleQueries(int[][] rectangle) {
        this.rectangle = rectangle;
    }

    public void updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) {
        history.add(new int[]{row1, col1, row2, col2, newValue});
    }

    public int getValue(int row, int col) {
        for (int i = history.size() - 1; i >= 0; --i) {
            int[] h = history.get(i);
            if (row >= h[0] && row <= h[2]
                && col >= h[1] && col <= h[3]) {
                return h[4];
            }
        }
        return rectangle[row][col];
    }
}

/**
 * Your SubrectangleQueries object will be instantiated and called as such:
 * SubrectangleQueries obj = new SubrectangleQueries(rectangle);
 * obj.updateSubrectangle(row1,col1,row2,col2,newValue);
 * int param_2 = obj.getValue(row,col);
 */
AI 代码解读

c

typedef struct {
    int value[100][100];
    int history[500][5];
    int history_size;
} SubrectangleQueries;


SubrectangleQueries *subrectangleQueriesCreate(int **rectangle, int rectangleSize, int *rectangleColSize) {
    SubrectangleQueries *obj = NULL;

    obj = (SubrectangleQueries *) malloc(sizeof(SubrectangleQueries));
    if (obj == NULL) {
        return NULL;
    }

    for (int i = 0; i < rectangleSize; ++i) {
        for (int j = 0; j < rectangleColSize[i]; ++j) {
            obj->value[i][j] = rectangle[i][j];
        }
    }

    return obj;
}

void
subrectangleQueriesUpdateSubrectangle(SubrectangleQueries *obj, int row1, int col1, int row2, int col2, int newValue) {
    int *h = obj->history[obj->history_size++];
    h[0] = row1;
    h[1] = col1;
    h[2] = row2;
    h[3] = col2;
    h[4] = newValue;
}

int subrectangleQueriesGetValue(SubrectangleQueries *obj, int row, int col) {
    for (int i = obj->history_size - 1; i >= 0; --i) {
        int *h = obj->history[i];
        if (row >= h[0] && row <= h[2]
            && col >= h[1] && col <= h[3]) {
            return h[4];
        }
    }
    return obj->value[row][col];
}

void subrectangleQueriesFree(SubrectangleQueries *obj) {
    free(obj);
}

/**
 * Your SubrectangleQueries struct will be instantiated and called as such:
 * SubrectangleQueries* obj = subrectangleQueriesCreate(rectangle, rectangleSize, rectangleColSize);
 * subrectangleQueriesUpdateSubrectangle(obj, row1, col1, row2, col2, newValue);

 * int param_2 = subrectangleQueriesGetValue(obj, row, col);

 * subrectangleQueriesFree(obj);
*/
AI 代码解读

c++

class SubrectangleQueries {
private:
    vector<vector<int>> rectangle;
    vector<vector<int>> history;
public:
    SubrectangleQueries(vector<vector<int>>& rectangle) : rectangle(rectangle) {
    }

    void updateSubrectangle(int row1, int col1, int row2, int col2, int newValue) {
        history.push_back({row1, col1, row2, col2, newValue});
    }

    int getValue(int row, int col) {
        for (int i = history.size() - 1; i >= 0; --i) {
            vector<int> h = history[i];
            if (row >= h[0] && row <= h[2]
                && col >= h[1] && col <= h[3]) {
                return h[4];
            }
        }
        return rectangle[row][col];
    }
};

/**
 * Your SubrectangleQueries object will be instantiated and called as such:
 * SubrectangleQueries* obj = new SubrectangleQueries(rectangle);
 * obj->updateSubrectangle(row1,col1,row2,col2,newValue);
 * int param_2 = obj->getValue(row,col);
 */
AI 代码解读

python

class SubrectangleQueries:

    def __init__(self, rectangle: List[List[int]]):
        self.rectangle = rectangle
        self.history = []

    def updateSubrectangle(self, row1: int, col1: int, row2: int, col2: int, newValue: int) -> None:
        self.history.append((row1, col1, row2, col2, newValue))


    def getValue(self, row: int, col: int) -> int:
        for i in range(len(self.history) - 1, -1, -1):
            row1, col1, row2, col2, val = self.history[i]
            if row1 <= row <= row2 and col1 <= col <= col2:
                return val

        return self.rectangle[row][col]


# Your SubrectangleQueries object will be instantiated and called as such:
# obj = SubrectangleQueries(rectangle)
# obj.updateSubrectangle(row1,col1,row2,col2,newValue)
# param_2 = obj.getValue(row,col)
AI 代码解读

go

type SubrectangleQueries struct {
    rectangle [][]int
    history   [][]int
}

func Constructor(rectangle [][]int) SubrectangleQueries {
    return SubrectangleQueries{rectangle: rectangle}
}

func (this *SubrectangleQueries) UpdateSubrectangle(row1 int, col1 int, row2 int, col2 int, newValue int) {
    this.history = append(this.history, []int{row1, col1, row2, col2, newValue})
}

func (this *SubrectangleQueries) GetValue(row int, col int) int {
    for i := len(this.history) - 1; i >= 0; i-- {
        h := this.history[i]
        if h[0] <= row && row <= h[2] && h[1] <= col && col <= h[3] {
            return h[4]
        }
    }
    return this.rectangle[row][col]
}


/**
 * Your SubrectangleQueries object will be instantiated and called as such:
 * obj := Constructor(rectangle);
 * obj.UpdateSubrectangle(row1,col1,row2,col2,newValue);
 * param_2 := obj.GetValue(row,col);
 */
AI 代码解读

rust

struct SubrectangleQueries {
  rectangle: Vec<Vec<i32>>,
  history: Vec<(i32, i32, i32, i32, i32)>,
}

/**
 * `&self` means the method takes an immutable reference.
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl SubrectangleQueries {

  fn new(rectangle: Vec<Vec<i32>>) -> Self {
    Self {rectangle, history: vec![]}
  }

  fn update_subrectangle(&mut self, row1: i32, col1: i32, row2: i32, col2: i32, new_value: i32) {
    self.history.push((row1, col1, row2, col2, new_value));
  }

  fn get_value(&self, row: i32, col: i32) -> i32 {
    for &(r1, c1, r2, c2, val) in self.history.iter().rev() {
      if r1 <= row && row <= r2 && c1 <= col && col <= c2 {
        return val
      }
    }
    self.rectangle[row as usize][col as usize]
  }
}

/**
 * Your SubrectangleQueries object will be instantiated and called as such:
 * let obj = SubrectangleQueries::new(rectangle);
 * obj.update_subrectangle(row1, col1, row2, col2, newValue);
 * let ret_2: i32 = obj.get_value(row, col);
 */
AI 代码解读

原题传送门:https://leetcode-cn.com/problems/subrectangle-queries/


非常感谢你阅读本文~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://developer.aliyun.com/profile/sqd6avc7qgj7y 博客原创~

相关文章
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
解锁分布式文件分享的 Java 一致性哈希算法密码
在数字化时代,文件分享成为信息传播与协同办公的关键环节。本文深入探讨基于Java的一致性哈希算法,该算法通过引入虚拟节点和环形哈希空间,解决了传统哈希算法在分布式存储中的“哈希雪崩”问题,确保文件分配稳定高效。文章还展示了Java实现代码,并展望了其在未来文件分享技术中的应用前景,如结合AI优化节点布局和区块链增强数据安全。
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
111 16
|
2月前
|
Java使用sql查询mongodb
通过MongoDB Atlas Data Lake或Apache Drill,可以在Java中使用SQL语法查询MongoDB数据。这两种方法都需要适当的配置和依赖库的支持。希望本文提供的示例和说明能够帮助开发者实现这一目标。
71 17
剖析基于Java算法驱动的智能局域网管控之道
本文探讨了基于Java语言的局域网控制方案,结合链表数据结构与令牌桶算法,解决设备管理和流量调度难题。通过链表灵活存储网络设备信息,实现高效设备管理;令牌桶算法则精准控制流量,确保网络平稳运行。二者相辅相成,为校园、企业等局域网提供稳固高效的控制体系,保障业务连续性和数据安全。
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
93 6
【潜意识Java】MyBatis中的动态SQL灵活、高效的数据库查询以及深度总结
本文详细介绍了MyBatis中的动态SQL功能,涵盖其背景、应用场景及实现方式。
200 6
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
71 5
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。