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

题目

给定一个 m x n 的整数矩阵 mat,我们需要找出从某个单元格出发可以访问的最大单元格数量。移动规则是可以从当前单元格移动到同一行或同一列的任何其他单元格,但目标单元格的值必须严格大于当前单元格的值。需要返回最大可访问的单元格数量。

示例

示例 1:

输入:mat = [[3,1],[3,4]]

输出:2

解释:从第 1 行、第 2 列的单元格开始,可以访问 2 个单元格。

示例 2:

输入:mat = [[1,1],[1,1]]

输出:1

解释:由于目标单元格必须严格大于当前单元格,只能访问 1 个单元格。

示例 3:

输入:mat = [[3,1,6],[-9,5,7]]

输出:4

解释:从第 2 行、第 1 列的单元格开始,可以访问 4 个单元格。

提示

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 10^5
  • 1 <= m * n <= 10^5
  • -10^5 <= mat[i][j] <= 10^5

解决方案

采用深度优先搜索(DFS)结合动态规划(DP)来解决此问题。用 dp[i][j] 表示从位置 (i, j) 出发可以访问的最大单元格数。

代码

c 复制代码
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(a,b) ((a) > (b) ? (a) : (b))

int matSize, matColSize;
int **mat, **dp;

bool isValid(int x, int y) {
    return x >= 0 && x < matSize && y >= 0 && y < matColSize;
}

int dfs(int x, int y) {
    if (dp[x][y] != 0) return dp[x][y];

    int maxLen = 1;

    for (int col = 0; col < matColSize; col++) {
        if (col != y && mat[x][col] > mat[x][y]) {
            maxLen = MAX(maxLen, 1 + dfs(x, col));
        }
    }

    for (int row = 0; row < matSize; row++) {
        if (row != x && mat[row][y] > mat[x][y]) {
            maxLen = MAX(maxLen, 1 + dfs(row, y));
        }
    }

    dp[x][y] = maxLen;
    return maxLen;
}

int maxIncreasingCells(int** matrix, int matrixSize, int* matrixColSize){
    mat = matrix;
    matSize = matrixSize;
    matColSize = *matrixColSize;

    dp = (int**)calloc(matSize, sizeof(int*));
    for (int i = 0; i < matSize; i++) {
        dp[i] = (int*)calloc(matColSize, sizeof(int));
    }

    int maxCells = 0;
    for (int i = 0; i < matSize; i++) {
        for (int j = 0; j < matColSize; j++) {
            maxCells = MAX(maxCells, dfs(i, j));
        }
    }

    for (int i = 0; i < matSize; i++) {
        free(dp[i]);
    }
    free(dp);

    return maxCells;
}

实现步骤

1. 初始化和输入处理

读取输入矩阵,并初始化 dp 数组。dp[i][j] 用于存储从位置 (i, j) 出发可以访问的最大单元格数。

c 复制代码
int matSize, matColSize;
int **mat, **dp;

dp = (int**)calloc(matSize, sizeof(int*));
for (int i = 0; i < matSize; i++) {
    dp[i] = (int*)calloc(matColSize, sizeof(int));
}

2. 定义有效移动检查函数

检查从当前单元格移动到目标单元格是否合法,即目标单元格的值必须严格大于当前单元格的值。

c 复制代码
bool isValid(int x, int y) {
    return x >= 0 && x < matSize && y >= 0 && y < matColSize;
}

3. 深度优先搜索(DFS)

  • 若 dp[x][y] 已计算,直接返回。
  • 遍历同一行和同一列中的单元格,若满足条件,递归计算并更新 dp[x][y]。
c 复制代码
int dfs(int x, int y) {
    if (dp[x][y] != 0) return dp[x][y];

    int maxLen = 1;

    // 遍历同一行中的其他单元格
    for (int col = 0; col < matColSize; col++) {
        if (col != y && mat[x][col] > mat[x][y]) {
            maxLen = MAX(maxLen, 1 + dfs(x, col));
        }
    }

    // 遍历同一列中的其他单元格
    for (int row = 0; row < matSize; row++) {
        if (row != x && mat[row][y] > mat[x][y]) {
            maxLen = MAX(maxLen, 1 + dfs(row, y));
        }
    }

    dp[x][y] = maxLen;
    return maxLen;
}

4. 主逻辑

  • 遍历矩阵每个单元格,计算从每个单元格出发可以访问的最大单元格数。
  • 更新并返回全局最大值。
c 复制代码
int maxIncreasingCells(int** matrix, int matrixSize, int* matrixColSize){
    mat = matrix;
    matSize = matrixSize;
    matColSize = *matrixColSize;

    dp = (int**)calloc(matSize, sizeof(int*));
    for (int i = 0; i < matSize; i++) {
        dp[i] = (int*)calloc(matColSize, sizeof(int));
    }

    int maxCells = 0;
    // 遍历每个单元格
    for (int i = 0; i < matSize; i++) {
        for (int j = 0; j < matColSize; j++) {
            maxCells = MAX(maxCells, dfs(i, j));
        }
    }

    for (int i = 0; i < matSize; i++) {
        free(dp[i]);
    }
    free(dp);

    return maxCells;
}

复杂度分析

  • 时间复杂度:O(m * n),每个单元格只被访问一次。
  • 空间复杂度 :O(m * n),用于存储 dp 数组。

结果

我尽力了。。。不愧是困难提题目

贴一个优化前的代码

c 复制代码
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define MAX(a,b) ((a) > (b) ? (a) : (b))
int gotoNext(int** dp, int matSize, int* matColSize, int** mat, int beginCol, int beginRow, int* tmpStepCnt, bool** isVisited)
{
    if(dp[beginCol][beginRow] != 0)
    {
        (*tmpStepCnt) += dp[beginCol][beginRow];
        return (*tmpStepCnt);
    }
    (*tmpStepCnt)++;
    isVisited[beginCol][beginRow] = true;
    int tmp_left = 0, tmp_right = 0, tmp_up = 0, tmp_down = 0;
    int left = 0, right = 0, up = 0, down = 0;
    int cnt = 0;
    for (int i = 1; i < matSize; i++)
    {
        if(beginCol + i <= matSize - 1 && !isVisited[beginCol + i][beginRow] && mat[beginCol + i][beginRow] > mat[beginCol][beginRow]) 
        {
            tmp_right = gotoNext(dp, matSize, matColSize, mat, beginCol + i, beginRow, &cnt, isVisited);
            right = MAX(tmp_right, right);
            cnt = 0;
            // printf("right = %d\n",right);
        }
        else
        {
            // // printf("cant goto [%d][%d]\n",beginCol + i, beginRow);
        }
        if(beginCol - i >= 0 && !isVisited[beginCol - i][beginRow] && mat[beginCol - i][beginRow] > mat[beginCol][beginRow]) 
        {
            tmp_left = gotoNext(dp, matSize, matColSize, mat, beginCol - i, beginRow, &cnt, isVisited);
            left = MAX(tmp_left, left);
            cnt = 0;
            // printf("left = %d\n",left);
        }
        else
        {
            // // printf("cant goto [%d][%d]\n",beginCol - i, beginRow);
        }
    }
    for (int i = 1; i < (*matColSize); i++)
    {
        if(beginRow + i <= (*matColSize) - 1 && !isVisited[beginCol][beginRow + i] && mat[beginCol][beginRow + i] > mat[beginCol][beginRow]) 
        {
            tmp_down = gotoNext(dp, matSize, matColSize, mat, beginCol, beginRow + i, &cnt, isVisited);
            down = MAX(tmp_down, down);
            cnt = 0;
            // printf("down = %d\n",down);
        }
        else
        {
            // // printf("cant goto [%d][%d]\n",beginCol, beginRow + i);
        }
        if(beginRow - i >= 0 && !isVisited[beginCol][beginRow - i] && mat[beginCol][beginRow - i] > mat[beginCol][beginRow])
        {
            tmp_up = gotoNext(dp, matSize, matColSize, mat, beginCol, beginRow - i, &cnt, isVisited);
            up = MAX(tmp_up, up);
            cnt = 0;
            // printf("up = %d\n",up);
        }
        else
        {
            // // printf("cant goto [%d][%d]\n",i, beginRow - i);
        }
    }
    isVisited[beginCol][beginRow] = false;
    (*tmpStepCnt) += MAX(MAX(left, right), MAX(up, down));
    return (*tmpStepCnt);
}

int maxIncreasingCells(int** mat, int matSize, int* matColSize){
    int stepCnt = 0;
    int **dp = (int**)calloc(matSize, sizeof(int*)); // 记录从某个格子开始走,可以走多少个格子。
    bool **isVisited = (bool**)calloc(matSize, sizeof(bool*)); // 记录某个格子是否被访问,防止死循环。
    for (int i = 0; i < matSize; i++)
    {
        dp[i] = (int*)calloc((*matColSize), sizeof(int)); // 记录从某个格子开始走,可以走多少个格子。
        isVisited[i] = (bool*)calloc((*matColSize), sizeof(bool)); // 记录某个格子是否被访问,防止死循环。
    }
    
    for (int i = 0; i < matSize; i++)
    {
        for (int j = 0; j < (*matColSize); j++)
        {
            int tmpStepCnt = 0;
            tmpStepCnt = gotoNext(dp, matSize, matColSize, mat, i, j, &tmpStepCnt, isVisited);
            stepCnt = MAX(tmpStepCnt, stepCnt);
            dp[i][j] = tmpStepCnt;
            // printf("dp[%d][%d] = %d\n", i,j,dp[i][j]);
        }
    }
    return stepCnt;
}

这个更惨,

相关推荐
東隅已逝,桑榆非晚1 小时前
算法6. 双指针法-查找总价格为目标的两个商品
c++·学习·算法
Eyfcom1 小时前
〖物联网终端实战 01〗UWB 室内高精度定位:仓储 AGV 与人员的厘米级轨迹追踪
物联网·算法·物流系统·快递系统·跨境物流快递系统·物联网终端实战
bro_Java6662 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法
爱喝雪碧的可乐2 小时前
MATLAB
开发语言·算法·matlab
叼烟扛炮3 小时前
Linux 学习笔记(六十):单线程的逆袭——epoll 高并发服务器实战
linux·服务器·网络·笔记·学习·算法
careathers4 小时前
【数据结构】基于比较的排序算法 - 交换排序
数据结构·算法·排序算法
文丑颜不良啊4 小时前
LeetCode2081~2100题目解析
java·leetcode
HUANGZHENXUAN1234 小时前
最大子矩阵和:从 O(n⁴) 到 O(n³) 的列压缩 + Kadane
c语言·前端
H.莓飛4 小时前
【C++】【STL】vector_OJ题
linux·服务器·开发语言·数据结构·c++·visual studio
Rabitebla4 小时前
【Linux操作系统】进程篇(十一):进程程序替换——从底层原理到 exec 函数族
linux·服务器·c++·笔记·学习·算法