IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java&C++题解与拓展——leetcode427.建立四叉树【二维vector初始化学习与使用】 -> 正文阅读

[数据结构与算法]Java&C++题解与拓展——leetcode427.建立四叉树【二维vector初始化学习与使用】

每日一题做题记录,参考官方和三叶的题解

题目要求

image.png
image.png

理解

哦题目好长……

  • 把矩阵递归四分,直到每个小块内的值相同(为叶子节点);
  • 叶子节点 i s L e a f = 1 isLeaf=1 isLeaf=1 v a l val val设为小块内的值(块内每个格子值相等);
  • 非叶子节点 i s L e a f = 0 isLeaf=0 isLeaf=0 v a l val val随便。

思路一:递归

  • 递归判断当前矩阵范围内值是否都相等
    • 相等则为叶子,返回(值, true)
    • 不相等则从中间划分为四个,分别再判断
  • 可以直接用左上角点 ( t l x , t l y ) (tlx, tly) (tlx,tly)和右下角点 ( b r x , b r y ) (brx, bry) (brx,bry)的坐标来划定矩阵范围
    • 划分时分别砍半横着 t l x + b r x 2 \frac{tlx+brx}{2} 2tlx+brx?、竖着 t l y + b r y 2 \frac{tly+bry}{2} 2tly+bry?

Java

class Solution {
    int[][] g;
    public Node construct(int[][] grid) {
        g = grid;
        int n = g.length;
        return DFS(0, 0, n, n);
    }

    Node DFS(int tlx, int tly, int brx, int bry) {
        boolean equ = true;
        int t = g[tlx][tly];
        // 块内所有值相等
        for(int i = tlx; i < brx && equ; ++i)
            for(int j = tly; j < bry && equ; ++j)
                if(g[i][j] != t)
                    equ = false;
        if(equ)
            return new Node(t == 1, true); // 叶子

        int nx = (brx + tlx) / 2, ny = (bry + tly) / 2; // 分割线
        Node root = new Node(
            true,
            false,
            DFS(tlx, tly, nx, ny),
            DFS(tlx, ny, nx, bry),
            DFS(nx, tly, brx, ny),
            DFS(nx, ny, brx, bry)
        );
              
        return root;
    }
}
  • 时间复杂度: O ( n 2 + n 2 × log ? n ) O(n^2+n^2\times\log n) O(n2+n2×logn),单次递归调用4个子递归,其规模为 n 2 × n 2 \frac{n}{2}\times\frac{n}{2} 2n?×2n?,复杂度共 4 O ( n 2 4 ) = O ( n 2 ) 4O(\frac{n^2}{4})=O(n^2) 4O(4n2?)=O(n2);判断块内所有值相等复杂度为 O ( n 2 ) O(n^2) O(n2),最多拆分 log ? n \log n logn次(也是需判断次数),所以递归内复杂度为 O ( n 2 × log ? n ) O(n^2\times\log n) O(n2×logn)
  • 空间复杂度: O ( 1 ) O(1) O(1),忽略递归的额外空间开销

C++

class Solution {
    vector<vector<int>> g;
public:
    Node* construct(vector<vector<int>>& grid) {
        g = grid;
        int n = g.size();
        return DFS(0, 0, n, n);
    }

    Node* DFS(int tlx, int tly, int brx, int bry) {
        bool equ = true;
        int t = g[tlx][tly];
        // 块内所有值相等
        for(int i = tlx; i < brx && equ; ++i)
            for(int j = tly; j < bry && equ; ++j)
                if(g[i][j] != t)
                    equ = false;
        if(equ)
            return new Node(t == 1, true); // 叶子

        int nx = (brx + tlx) / 2, ny = (bry + tly) / 2; // 分割线
        Node* root = new Node(
            true,
            false,
            DFS(tlx, tly, nx, ny),
            DFS(tlx, ny, nx, bry),
            DFS(nx, tly, brx, ny),
            DFS(nx, ny, brx, bry)
        );
              
        return root;
    }
};
  • 时间复杂度: O ( n 2 + n 2 × log ? n ) O(n^2+n^2\times\log n) O(n2+n2×logn),单次递归调用4个子递归,其规模为 n 2 × n 2 \frac{n}{2}\times\frac{n}{2} 2n?×2n?,复杂度共 O ( n 2 ) O(n^2) O(n2);判断块内所有值相等复杂度为 O ( n 2 ) O(n^2) O(n2),最多拆分 log ? n \log n logn次(也是需判断次数),所以递归内复杂度为 O ( n 2 × log ? n ) O(n^2\times\log n) O(n2×logn)
  • 空间复杂度: O ( 1 ) O(1) O(1),忽略递归的额外空间开销

思路二:递归+前缀和

  • 前面判断块内所有值相等的暴力方法可以采用前缀和优化
  • 记录内容其实为每一部分的面积,为 0 0 0或为 当 前 块 内 格 子 数 当前块内格子数 则相同(为叶子),否则划分判断

Java

class Solution {
    int[][] g;
    int[][] pre = new int[70][70];
    public Node construct(int[][] grid) {
        g = grid;
        int n = g.length;
        // 前缀和
        for(int i = 1; i <= n; ++i) 
            for(int j = 1; j <= n; ++j)
                pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + grid[i - 1][j - 1];

        return DFS(0, 0, n, n);
    }

    Node DFS(int tlx, int tly, int brx, int bry) {
        int tot = pre[brx][bry] - pre[brx][tly] - pre[tlx][bry] + pre[tlx][tly];
        // 叶子
        if(tot == 0)
            return new Node(false, true);
        else if(tot == (brx - tlx) * (bry - tly))
            return new Node(true, true);
       
        int nx = (tlx + brx) / 2, ny = (tly + bry) / 2; // 分割线
        Node root = new Node(
            true,
            false,
            DFS(tlx, tly, nx, ny),
            DFS(tlx, ny, nx, bry),
            DFS(nx, tly, brx, ny),
            DFS(nx, ny, brx, bry)
        );
        return root;
    }
}
  • 时间复杂度: O ( n 2 + log ? n ) O(n^2+\log n) O(n2+logn),递归复杂度和上面一样为 O ( n 2 ) O(n^2) O(n2),二维前缀和预处理复杂度也为 O ( n 2 ) O(n^2) O(n2)递归内判断复杂度O(1),拆分O(log n)次【这部分是基于上一方法思路的个人胡乱分析,其实小于前面部分可以拿掉写成 O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n 2 ) O(n^2) O(n2),二维前缀和所需

C++

class Solution {
private:
    vector<vector<int>> g;
    vector<vector<int>> pre = vector<vector<int>> (70, vector<int>(70, 0));
public:
    Node* construct(vector<vector<int>>& grid) {
        g = grid;
        int n = g.size();
        // 前缀和
        for(int i = 1; i <= n; ++i) 
            for(int j = 1; j <= n; ++j)
                pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + grid[i - 1][j - 1];

        return DFS(0, 0, n, n);
    }

    Node* DFS(int tlx, int tly, int brx, int bry) {
        int tot = pre[brx][bry] - pre[brx][tly] - pre[tlx][bry] + pre[tlx][tly];
        // 叶子
        if(tot == 0)
            return new Node(false, true);
        else if(tot == (brx - tlx) * (bry - tly))
            return new Node(true, true);

        int nx = (brx + tlx) / 2, ny = (bry + tly) / 2; // 分割线
        Node* root = new Node(
            true,
            false,
            DFS(tlx, tly, nx, ny),
            DFS(tlx, ny, nx, bry),
            DFS(nx, tly, brx, ny),
            DFS(nx, ny, brx, bry)
        );
              
        return root;
    }
};
  • 时间复杂度: O ( n 2 + log ? n ) O(n^2+\log n) O(n2+logn),递归复杂度和上面一样为 O ( n 2 ) O(n^2) O(n2),二维前缀和预处理复杂度也为 O ( n 2 ) O(n^2) O(n2)递归内判断复杂度为O(1),拆分O(\log n)$次【这部分是基于上一方法思路的个人胡乱分析,其实小于前面部分可以拿掉写成 O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n 2 ) O(n^2) O(n2),二维前缀和所需

二维vector初始化

  • 学习参考链接
  • 格式为vector<vector<int>> vec(n, vector<int>(m, 0)); n n n为容器大小, m m m为容器内每个值大小。
  • 但是直接初始化全局变量会报错:

    expected parameter declarator

    • 意为编译器无法区分该语句是在声明变量还是函数,所以可以类比java的初始化方法,即
    vector<vector<int>> vec = vector<vector<int>> (n, vector<int>(m, 0));
    
    • 其他解决方案参考这里

总结

递归应用题目,结束条件的+1、-1卡了一会,要理清思路看好是长度还是坐标。


欢迎指正与讨论!
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:57:52  更:2022-05-01 16:01:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:58:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码