【算法】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

样例 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

提示

  • 最多有 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);
 */

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);
*/

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);
 */

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)

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);
 */

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);
 */

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


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

相关文章
|
17天前
|
人工智能 安全 Java
Java和Python在企业中的应用情况
Java和Python在企业中的应用情况
45 7
|
13天前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
116 67
|
13天前
|
存储 搜索推荐 Python
用 Python 实现快速排序算法。
快速排序的平均时间复杂度为$O(nlogn)$,空间复杂度为$O(logn)$。它在大多数情况下表现良好,但在某些特殊情况下可能会退化为最坏情况,时间复杂度为$O(n^2)$。你可以根据实际需求对代码进行调整和修改,或者尝试使用其他优化策略来提高快速排序的性能
110 61
|
14天前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
101 63
|
7天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
60 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
25天前
|
算法 关系型数据库 MySQL
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
在分布式系统中,确保每个节点生成的 ID 唯一且高效至关重要。Snowflake 算法由 Twitter 开发,通过 64 位 long 型数字生成全局唯一 ID,包括 1 位标识位、41 位时间戳、10 位机器 ID 和 12 位序列号。该算法具备全局唯一性、递增性、高可用性和高性能,适用于高并发场景,如电商促销时的大量订单生成。本文介绍了使用 Go 语言的 `bwmarrin/snowflake` 和 `sony/sonyflake` 库实现 Snowflake 算法的方法。
33 1
分布式唯一ID生成:深入理解Snowflake算法在Go中的实现
|
17天前
|
Java 程序员 开发工具
在比较Java和Python哪个更易学
在比较Java和Python哪个更易学
29 4
|
17天前
|
Java 程序员 Python
Java和Python
Java和Python
22 2
|
25天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
74 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
25天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
68 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型