Leetcode 2713. 矩阵中严格递增的单元格数(DFS DP)

Leetcode 2713. 矩阵中严格递增的单元格数

DFS

容易想到,枚举每个点作为起点,向同行同列的可跳跃点dfs,维护全局变量记录可达的最远距离

超时,通过样例193 / 566

class Solution {
    int res = 0;
    
    public void dfs(int[][] mat, int x, int y, int step){
        step ++;
        res = Math.max(res, step);
        int n = mat.length;
        int m = mat[0].length;
        int num = mat[x][y];
        for(int i = 0; i < n; i ++){
            if(mat[i][y] > num){
                dfs(mat, i, y, step);
            }
        }
        for(int j = 0; j < m; j ++){
            if(mat[x][j] > num){
                dfs(mat, x, j, step);
            }
        }
        return;
    }

    public int maxIncreasingCells(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        for(int i = 0 ; i < n; i ++){
            for(int j = 0 ; j < m; j ++){
                dfs(mat, i, j, 0);
            }
        }
        return res;
    }
}

DFS+记忆化搜索

在DFS中注意到,存在很多重复计算,无论以哪个点作为起点,当跳跃到(x, y)点后,后续的最远距离是固定的,若在其他的起点中已经计算过这个数值,则记录下来直接取用

使用mem[ i ][ j ]记录坐标(i, j)位置所能跳跃的最大距离,在进入DFS后,若这个点已经计算过,即mem[ i ][ j ]非0,则直接取用。若没有计算过,则进行DFS,并在DFS结束后更新mem[ i ][ j ]

超时,通过样例558 / 566

class Solution {
    int mem[][];
    // dfs函数返回(x,y)坐标可达最远距离,包含自身,最少为1
    public int dfs(int[][] mat, int x, int y){
        if(mem[x][y] != 0){
            return mem[x][y];
        }
        int n = mat.length;
        int m = mat[0].length;
        int res = 1;
        int num = mat[x][y];
        for(int i = 0; i < n; i ++){
            if(mat[i][y] > num){
                int ans = dfs(mat, i, y);
                res = Math.max(res, ans + 1);
            }
        }
        for(int j = 0; j < m; j ++){
            if(mat[x][j] > num){
                int ans = dfs(mat, x, j);
                res = Math.max(res, ans + 1);
            }
        }
        mem[x][y] = res;
        return res;
    }

    public int maxIncreasingCells(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        mem = new int [n][m];
        int res = 0;
        for(int i = 0 ; i < n; i ++){
            for(int j = 0 ; j < m; j ++){
                res = Math.max(res, dfs(mat, i, j));
            }
        }
        return res;
    }
}

DP

经过优化无法使用DFS通过所有样例,重新分析问题

对于点(x, y)来说,以其作为起点,该点所能到达的最远距离,取决于该行和该列中其他点所能到达的最远距离,即为Max(行可达最远,列可达最远)+1

但移动规则为只能向更大的点进行移动,若每次移动前对行列所有元素都进行检查同样会造成时间浪费,因此将n*m个位置根据值进行降序排序,从大到小进行处理

这样带来的好处是,无需考虑跳跃规则问题,当处理一个元素时,已经记录的行可达最远的点是一定大于它的,一定可以向其移动

另一方面,只需求出移动的最远距离,因此无需记录一次移动使用哪个位置转移过来的,只需要知道此次移动的距离是多少就可以,即第 i 行的行可达最远只需要O(1)的空间,来实时维护此时该行已经处理过的最远距离,列同理

由此构思所需要的空间
dp[ i ][ j ] 记录(i, j)位置为起点,所能移动的最远距离
rowMax[ i ] 记录第 i 行此时已经存在的最远距离,即该行中存在一个点,该点为起点所能移动的距离最远为rowMax[ i ],初始化为0
colMax[ j ] 记录第 j 列此时已经存在的最远距离,即该列中存在一个点,该点为起点所能移动的距离最远为colMax[ i ],初始化为0
则dp[ i ][ j ] = Max{ rowMax[ i ], colMax[ j ] } + 1
计算后更新rowMax[ i ] 和 colMax[ j ]

在这里插入图片描述

起点7:dp = max(0, 0) + 1 = 1,更新rowMax[ 1 ] = 1,更新colMax[ 2 ] = 1
起点6:dp = max(0, 1) + 1 = 2,更新rowMax[ 0 ] = 2,更新colMax[ 2 ] = 2
起点5:dp = max(1, 0) + 1 = 2,更新rowMax[ 1 ] = 2,更新colMax[ 1 ] = 2
起点3:dp = max(2, 0) + 1 = 3,更新rowMax[ 0 ] = 3,更新colMax[ 0 ] = 3
起点1:dp = max(3, 2) + 1 = 4,更新rowMax[ 0 ] = 4,更新colMax[ 1 ] = 4
起点-9:dp = max(2, 3) + 1 = 4,更新rowMax[ 1 ] = 4,更新colMax[ 0 ] = 4

在这里插入图片描述
另外注意,存在相同元素,此时计算dp时不应更新rowMax,违背了rowMax的定义“该行内存在一点,以其为起点所答的最远距离为rowMax[ i ],dp[ i ] [ j ] = rowMax + 1”,因为对于同样的元素来说,他们之间是不可达的,因此对于相同元素来说,此时更新rowMax会导致从值k移动到值k 的情况发生

因此将相同元素作为一批同时处理,其间使用rowMax计算dp,而定义一个新数组rowTemp来临时记录rowMax应有的变化,当这一批值相同的元素dp计算结束后,再将rowTemp赋值给rowMax以用于后续的计算,colMax同理

class Solution {
	// Pair类记录一个点的值和坐标,用于排序
    public class Pair{
        private int val;
        private int x;
        private int y;

        public Pair(int val, int x, int y) {
            this.val = val;
            this.x = x;
            this.y = y;
        }
    }

    public int maxIncreasingCells(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        Pair pairs[] = new Pair[n * m];
        int index = 0;
        for(int i = 0 ; i < n; i ++){
            for(int j = 0; j < m; j ++){
                pairs[index++] = new Pair(mat[i][j], i, j);
            }
        }
		// 降序排序所有点
        Arrays.sort(pairs, (p1, p2) -> Integer.compare(p2.val, p1.val));
        int rowMax[] = new int [n];
        int colMax[] = new int [m];
        int dp[][] = new int [n][m];
        int res = 0;
        for(int i = 0 ; i < n*m; i ++){
            int val = pairs[i].val;
            int x = pairs[i].x;
            int y = pairs[i].y;
            // 相同元素情况
            if(i+1 < n*m && pairs[i+1].val == val){
                int l = i;
                int r = i + 1;
                // 确定范围
                while(r < n*m && pairs[r].val == val)
                    r ++;
                // rowMax副本
                int rowTemp[] = rowMax.clone();
                int colTemp[] = colMax.clone();
                // 统一处理计算dp
                for(int k = l; k < r; k ++){
                    int kx = pairs[k].x;
                    int ky = pairs[k].y;
                    int kval = pairs[k].val;
                    dp[kx][ky] = Math.max(rowMax[kx], colMax[ky]) + 1;
                    res = Math.max(res, dp[kx][ky]);

                    // 将该行最远距离的变化暂存在rowTemp,保持rowMax不变
                    rowTemp[kx] = Math.max(rowTemp[kx], dp[kx][ky]);
                    colTemp[ky] = Math.max(colTemp[ky], dp[kx][ky]);
                }
                // dp计算后将rowMax值更新
                for(int j = 0; j < n; j ++){
                    rowMax[j] = rowTemp[j];
                }
                for(int j = 0; j < m; j ++){
                    colMax[j] = colTemp[j];
                }
                i = r - 1;
            }
            // 不同元素情况直接计算
            else{
                dp[x][y] = Math.max(rowMax[x], colMax[y]) + 1;
                res = Math.max(res, dp[x][y]);
                rowMax[x] = dp[x][y];
                colMax[y] = dp[x][y];
            }
        }
        return res;
    }
}

相同元素处理部分写的比较繁琐了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/736183.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv中凸包运算函数convexHull()的使用

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 1.功能描述 该函数cv::convexHull用于寻找一组二维点集的凸包&#xff0c;采用的是Sklansky算法[242]&#xff0c;当前实现中具有O(N logN)的时间复杂度。 1…

SuiNS发布子名及新命名标准,推动Web3身份结构的进步

SuiNS子名是Sui Name Service的强大扩展&#xff0c;最近与新命名标准一起发布。子名允许用户在一个主要的SuiNS名下创建额外的自定义身份&#xff0c;而无需额外费用。用户 gia 可以创建如 gaminggia 或 lendinggia 这样的子名&#xff0c;从而增强个人组织和支持群组与组织的…

机器人学习和研究的物质基础包含哪些内容?

为啥写这个&#xff1f; 在很多博客里面提及物质基础&#xff0c;没想到询问的也非常多&#xff0c;写一篇详细一点的。 之前的故事 不合格且失败机器人讲师个人理解的自身课程成本情况-CSDN博客 迷失自我无缘多彩世界-2024--CSDN博客 物质基础与情绪稳定的关系-CSDN博客 …

docker搭建mongo分片集群

1、mongo分片集群 MongoDB分片集群是一种可扩展的数据库架构&#xff0c;用于处理大量数据和高并发访问。它将数据分成多个分片&#xff0c;并将这些分片分布在多个服务器上&#xff0c;从而实现数据的平衡存储和并行处理 。 通过使用MongoDB的分片集&#xff0c;可以实现数据…

ViT:5 Knowledge Distillation

实时了解业内动态&#xff0c;论文是最好的桥梁&#xff0c;专栏精选论文重点解读热点论文&#xff0c;围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调或者LLM背后的基础模型重新阅读。而最新科技&#xff08;Mamba,xLSTM,KAN&#xff09;…

基于SpringBoot+Vue汽车配件销售管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

[SAP ABAP] 读取内表数据

1.读取单条数据 1.1 索引查找 语法格式 READ TABLE <itab> INTO <wa> INDEX <idx>.<itab>&#xff1a;代表内表 <wa>&#xff1a;代表工作区 <idx>&#xff1a;代表索引值 示例1 结果显示&#xff1a; 1.2 关键字查找 READ TABLE <…

JVM专题三:Java代码如何运行

通过前面的第一篇文章&#xff0c;对JVM整体脉络有了一个大概了解。第二篇文章我们通过对高级语言低级语言不同特性的探讨引出了Java的编译过程。有了前面的铺垫&#xff0c;咱们今天正式进入Java到底是如何运行起来的探讨。 目前大部分公司都是使用maven作为包管理工具&#x…

【华东南AWDP】第十七届全国大学生信息安全竞赛 CISCN 2024 创新实践能力赛区域赛 部分题解WP

前言&#xff1a;这次区域赛AWDP安恒作为支持&#xff0c;赛制风格遵循安恒&#xff0c;一小时check一次。室温35在室内坐了8小时&#xff0c;午饭是藿香正气水拌冰水。这场总体下来中规中矩吧。 WEB-welcome-BREAK CtrlU拿到flag WEB-submit-BREAK 文件上传&#xff0c;简单…

threejs视频融合 webgl

threejs三维视频融合 let objList []; const clock new THREE.Clock(); const container document.getElementById( container );const stats new Stats(); container.appendChild( stats.dom );const renderer new THREE.WebGLRenderer( { antialias: true } ); rendere…

时序预测 | Matlab基于Transformer多变量时间序列多步预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于Transformer多变量时间序列多步预测&#xff1b; 2.多变量时间序列数据集&#xff08;负荷数据集&#xff09;&#xff0c;采用前96个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&#xff1b; 3…

sql资料库

1、distinct(关键词distinct用于返回唯一不同的值)&#xff1a;查询结果中去除重复行的关键字 select distinct(university) from user_profile select distinct university from user_profile distinct是紧跟在select后面的&#xff0c;不能在其他位置&#xff0c;不然就…

287 寻找重复数-类似于环形链表II

题目 给定一个包含 n 1 个整数的数组 nums &#xff0c;其数字都在 [1, n] 范围内&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一个重复的整数。 假设 nums 只有 一个重复的整数 &#xff0c;返回 这个重复的数 。 你设计的解决方案必须 不修改 数组 nums…

光纤传感器十大品牌

十大光纤传感器品牌-光纤光栅传感器厂家哪家好-Maigoo品牌榜

如和完全免费快速访问外网?有亿点点不便利罢了

很鸡肋&#xff0c;但是可以试试 这个手机是真的可以使用谷歌的 不得不说有点意思&#xff0c;但肯定没啥用 地址跳转

软考高级论文真题“论湖仓一体架构及其应用”

论文真题 随着5G、大数据、人工智能、物联网等技术的不断成熟&#xff0c;各行各业的业务场景日益复杂&#xff0c;企业数据呈现出大规模、多样性的特点&#xff0c;特别是非结构化数据呈现出爆发式增长趋势。在这一背景下&#xff0c;企业数据管理不再局限于传统的结构化OLTP…

前端自动化

前端自动化的内容 自动化代码检查自动化测试自动化构建自动化部署自动化文档 前端自动化的最佳实践

【C#】使用数字和时间方法ToString()格式化输出字符串显示

在C#编程项目开发中&#xff0c;几乎所有对象都有格式化字符串方法&#xff0c;其中常见的是数字和时间的格式化输出多少不一样&#xff0c;按实际需要而定吧&#xff0c;现记录如下&#xff0c;以后会用得上。 文章目录 数字格式化时间格式化 数字格式化 例如&#xff0c;保留…

.NET C# 使用GDAL读取FileGDB要素类

.NET C# 使用GDAL读取FileGDB要素类 目录 .NET C# 使用GDAL读取FileGDB要素类1 环境2 Nuget3 Code 1 环境 VisualStudio2022 .NET6 GDAL 3.7.5 2 Nuget 3 Code using OSGeo.OGR; using OSGeo.OSR;namespace TestGDAL {internal class Program{static void Main(string[] a…

操作系统实验四:openEuler安装(openEuler配置静态网络、编写C或C++)

目录 一、实验要求 二、具体任务安排 1.安装openEuler &#xff08;1&#xff09;下载openEuler镜像 &#xff08;2&#xff09;使用vmware安装openEuler 2.在openEuler中编写C或者C测试程序 &#xff08;1&#xff09;安装g环境 &#xff08;2&#xff09;开始程序编码…