【map】【动态规划】LeetCode2713:矩阵中严格递增的单元格数

简介: 【map】【动态规划】LeetCode2713:矩阵中严格递增的单元格数

题目

给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat,你可以选择任一单元格作为 起始单元格 。

从起始单元格出发,你可以移动到 同一行或同一列 中的任何其他单元格,但前提是目标单元格的值 严格大于 当前单元格的值。

你可以多次重复这一过程,从一个单元格移动到另一个单元格,直到无法再进行任何移动。

请你找出从某个单元开始访问矩阵所能访问的 单元格的最大数量 。

返回一个表示可访问单元格最大数量的整数。

示例 1:

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

输出:2

解释:上图展示了从第 1 行、第 2 列的单元格开始,可以访问 2 个单元格。可以证明,无论从哪个单元格开始,最多只能访问 2 个单元格,因此答案是 2 。

示例 2:

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

输出:1

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

示例 3:

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

输出:4

解释:上图展示了从第 2 行、第 1 列的单元格开始,可以访问 4 个单元格。可以证明,无论从哪个单元格开始,最多只能访问 4 个单元格,因此答案是 4 。

参数范围

m == mat.length

n == mat[i].length

1 <= m, n <= 105

1 <= m * n <= 105

-105 <= mat[i][j] <= 105

分析

时间复杂度: O(mnlogmn)。初始化数据时间复杂度:O(nmlogmn)。枚举所有单元格时间复杂度O(mn),处理每个单元格,时间复杂度O(n)。

变量解析

mValueToRowCols 各值对应的行列,按值降序排序
vRowMax 大于当前值的各行最大递增单元格数
vColMax 大于当前值的各列最大递增单元格数
vBuf 当前值各行列的最大递增单元格数

代码

class Solution {
public:
  int maxIncreasingCells(vector<vector<int>>& mat) {
    m_r = mat.size();
    m_c = mat.front().size();
    std::map<int, vector<pair<int, int>>,greater<int>> mValueToRowCols;
    for (int r = 0; r < m_r ;r++)
    {
      for (int c = 0; c < m_c ; c++)
      {
        mValueToRowCols[mat[r][c]].emplace_back(r, c);
      }
    }
    vector<int> vRowMax(m_r), vColMax(m_c);
    vector<tuple<int, int, int>> vBuf;
    for (const auto& [tmp, v] : mValueToRowCols)
    {     
      for (const auto& [r, c] : v)
      {
        const int iMax = max(vRowMax[r], vColMax[c]) + 1;
        vBuf.emplace_back(r, c, iMax);        
      }
      for (const auto& [r, c, iMax] : vBuf)
      {
        vRowMax[r] = max(vRowMax[r], iMax);
        vColMax[c] = max(vColMax[c], iMax);
      }
      vBuf.clear();
    }
    return *std::max_element(vRowMax.begin(), vRowMax.end());
  }
  int m_r, m_c;
};

测试用例

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    assert(v1[i] == v2[i]);
  }
}
template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
int main()
{
  vector<vector<int>> mat;
  {
    Solution slu;
    mat = { {3,1},{3,4} };
    auto res = slu.maxIncreasingCells(mat);
    Assert(2, res);
  }
  {
    Solution slu;
    mat = { {1,1},{1,1} };
    auto res = slu.maxIncreasingCells(mat);
    Assert(1, res);
  }
  {
    Solution slu;
    mat = mat = { {3,1,6},{-9,5,7} };
    auto res = slu.maxIncreasingCells(mat);
    Assert(4, res);
  }
  {
    Solution slu;
    mat = mat = { {5, 2, 9},{-6, 2, -5},{-1, 0, -5} };
    auto res = slu.maxIncreasingCells(mat);
    Assert(6, res);
  }
}

超时代码示例

vector<int> vRowMax(m_r), vColMax(m_c);
    for (const auto& [tmp, v] : mValueToRowCols)
    {
      vector<int> vCurRowMax = vRowMax, vCurColMax = vColMax;
      for (const auto& [r, c] : v)
      {
        const int iMax = max(vRowMax[r], vColMax[c]) + 1;
        vCurRowMax[r]= max(vCurRowMax[r],iMax);
        vCurColMax[c] = max(vCurColMax[r],iMax);
      }
      vCurRowMax.swap(vRowMax);
      vCurColMax.swap(vColMax);
    }

vector 构造函数比较费事,执行mn次会超时。

2023年6月旧代码

class Solution {
public:
int maxIncreasingCells(vector& mat)
{
m_r = mat.size();
m_c = mat[0].size();
std::map < int, vector>,std::greater> mValueRowCol;
for (int r = 0; r < m_r; r++)
{
for (int c = 0; c < m_c; c++)
{
mValueRowCol[mat[r][c]].emplace_back(make_pair( r, c ));
}
}
vector vPreRows(m_r, 0), vPreCols(m_c, 0);
int iMaxRet = 0;
std::queue > que;
for ( auto it : mValueRowCol)
{
for (const auto& pr : it.second)
{
int iRet = std::max(vPreRows[pr.first],vPreCols[pr.second])+1 ;
iMaxRet = max(iMaxRet, iRet);
que.emplace(pr.first, pr.second, iRet);
}
while (que.size())
{
const int r = get<0>(que.front());
const int c = get<1>(que.front());
const int iRet = get<2>(que.front());
que.pop();
vPreRows[r] = max(vPreRows[r] ,iRet);
vPreCols[c] = max(vPreCols[c],iRet);
}
}
return iMaxRet;
}
int m_r, m_c;

};


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。



相关文章
|
3月前
|
存储 算法 NoSQL
LeetCode第73题矩阵置零
文章介绍了LeetCode第73题"矩阵置零"的解法,通过使用矩阵的第一行和第一列作为标记来记录哪些行或列需要置零,从而在不增加额外空间的情况下解决问题。
LeetCode第73题矩阵置零
|
21天前
|
算法 C++
Leetcode第59题(螺旋矩阵2)
这篇文章介绍了解决LeetCode第59题“螺旋矩阵II”的算法,通过C++编程实现按顺时针顺序填充一个n x n的正方形矩阵。
14 0
|
3月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
49 6
|
3月前
|
算法 JavaScript Python
【Leetcode刷题Python】79. 单词搜索和剑指 Offer 12. 矩阵中的路径
Leetcode第79题"单词搜索"的Python解决方案,使用回溯算法在给定的二维字符网格中搜索单词,判断单词是否存在于网格中。
35 4
|
3月前
|
算法 Python
【Leetcode刷题Python】73. 矩阵置零
本文介绍了LeetCode第73题的解法,题目要求在给定矩阵中将所有值为0的元素所在的行和列全部置为0,并提供了一种原地算法的Python实现。
28 0
【Leetcode刷题Python】73. 矩阵置零
|
3月前
|
算法 Python
【Leetcode刷题Python】300. 最长递增子序列
LeetCode 300题 "最长递增子序列" 的两种Python解决方案:一种使用动态规划,另一种使用贪心算法结合二分查找。
33 1
|
3月前
|
算法 Java
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
38 0
|
3月前
|
Python
【Leetcode刷题Python】674. 最长连续递增序列
LeetCode 674题 "最长连续递增序列" 的Python解决方案,使用动态规划算法找出给定整数数组中最长连续递增子序列的长度。
86 0
|
5月前
|
缓存
力扣每日一题 6/14 动态规划+数组
力扣每日一题 6/14 动态规划+数组
34 1
|
5月前
|
算法 索引
力扣每日一题 6/28 动态规划/数组
力扣每日一题 6/28 动态规划/数组
49 0