8.27 网格memo

 

 

lc329

计算矩阵中最长递增路径长度

 

尝试从矩阵每个位置出发,int dfs() 往上下左右四个方向找严格递增的路径

      ret=max(ret,dfs(x,y)+1);

      return memo[i][j]=ret;

返回所有路径里的最长长度 

class Solution 

{

public:

    int dx[4]={0,0,1,-1};

    int dy[4]={1,-1,0,0};

    int m,n;

    vector<vector<int>> memo;

    vector<vector<int>> matrix;

 

    int longestIncreasingPath(vector<vector<int>>& matrix) 

    {

        this->matrix=matrix;

        m=matrix.size();

        n=matrix[0].size();

       

        int cnt=0;

        memo.resize(m,vector<int>(n,0));

 

        for(int i=0;i<m;i++)

        {

            for(int j=0;j<n;j++)

            {

               cnt=max(cnt,dfs(i,j));

            }

        }

        return cnt;

 

    }

 

    int dfs(int i,int j)

    {

        if(memo[i][j]) return memo[i][j];

        

        int ret=1; //init

        

        for(int k=0;k<4;k++)

        {

            int x=i+dx[k],y=j+dy[k];

            if(x>=0 && x<m && y>=0 && y<n

            && matrix[x][y]>matrix[i][j])

            {

                ret=max(ret,dfs(x,y)+1);

            }

        }

      return memo[i][j]=ret;

    } 

};

 

lc3459

int  dfs  沿着某个方向一步步探路,符合规则(值对、没越界)就接着走,还能处理 “转一次弯” 的情况

同时用  memo  避免重复计算,(memo[i][j][k]: 从  (i,j)  位置往第  k  个方向走的最长有效长度)

1. 整体思路

 代码要在一个由 0、1、2 组成的二维矩阵里,找符合 “V 形对角线段” 规则的最长线段。

核心逻辑:从每个值为 1 的位置出发,沿着四个可能的对角方向(比如↘、↙、↖、↗ 这类斜线方向)去探索,按照 2、0、2、0…… 的序列模式走,还能最多右转一次 90 度弯,最后找出所有情况里最长的线段长度。

class Solution {
static constexpr int DIRS[4][2] = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}};

public:
int lenOfVDiagonal(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
vector memo(m, vector<array<int, 4>>(n));

        auto dfs = [&](this auto&& dfs, int i, int j, int k, bool can_turn, int target) -> int

{
i += DIRS[k][0];
j += DIRS[k][1];


if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != target) {
return 0;
}


// 只在 can_turn=false 时读取和写入 memo
if (!can_turn && memo[i][j][k]) {
return memo[i][j][k];
}


int res = dfs(i, j, k, can_turn, 2 - target) + 1; //延此方向往下走


if (!can_turn) {
return memo[i][j][k] = res;
}


int maxs[4] = {m - i, j + 1, i + 1, n - j}; // 理论最大值(走到底)
k = (k + 1) % 4;//顺时针


// 优化二:如果理论最大值没有超过 res,那么不递归
if (min(maxs[k], maxs[(k + 3) % 4]) > res) {
res = max(res, dfs(i, j, k, false, 2 - target) + 1);    //尝试转后,还是维护最大
}
return res;
};

 

        int ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] != 1) 
continue;

int maxs[4] = {m - i, j + 1, i + 1, n - j}; // 理论最大值(走到底)
for (int k = 0; k < 4; k++) { 
// 优化一:如果理论最大值没有超过 ans,那么不递归
if (maxs[k] > ans) {
ans = max(ans, dfs(i, j, k, true, 2) + 1);
}
}
}
}
return ans;
}
};

 

2. 解释

 (1)方向定义

 static constexpr int DIRS[4][2] = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}};

 预先定义好的 4 种对角移动方向 

 

(2)记忆化搜索( memo  数组)

 vector memo(m, vector<array<int, 4>>(n));

 //memo  是用来 缓存已经计算过的结果 ,避免重复计算。比如从  (i,j)  位置往第  k  个方向走的最长有效长度,算过一次就存起来,下次再碰到就直接用,能提升效率。

 

(3)深度优先搜索( dfs  函数)

 auto dfs = [&](this auto&& dfs, int i, int j, int k, bool can_turn, int target) -> int {

    // 先沿着当前方向走一步,更新坐标

    i += DIRS[k][0];

    j += DIRS[k][1];

    

    if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != target) {

        return 0;

    }

    // 如果还不能转弯(can_turn=false),看看缓存里有没有结果,有的话直接返回

    if (!can_turn && memo[i][j][k]) {

        return memo[i][j][k];

    }

 

    // 能走到这,说明当前格子有效,接着往下一步找,递归调用 dfs,同时切换下一个要找的 target(2 变 0,0 变 2 )

    int res = dfs(i, j, k, can_turn, 2 - target) + 1;

 

    // 如果还不能转弯,就把当前算出来的结果存到 memo 里,方便后续复用

    if (!can_turn) {

        return memo[i][j][k] = res;

    }

    // 下面是处理 “可以转弯” 的情况

    int maxs[4] = {m - i, j + 1, i + 1, n - j}; 

    // 切换方向(右转 90 度,对应 k = (k + 1) % 4 )

    k = (k + 1) % 4;

    // 优化:如果理论上转完弯能走的长度,还没当前 res 长,就不递归了,省点时间

    if (min(maxs[k], maxs[(k + 3) % 4]) > res) {

        // 转弯后,不能再转了(can_turn 设为 false ),递归计算新方向的长度,然后和当前 res 比,取大的

        res = max(res, dfs(i, j, k, false, 2 - target) + 1);

    }

    return res;

};

 简单说

dfs  沿着某个方向一步步探路,符合规则(值对、没越界)就接着走,还能处理 “转一次弯” 的情况

同时用  memo  避免重复计算,(memo[i][j][k]: 从  (i,j)  位置往第  k  个方向走的最长有效长度)

 

(4)主逻辑遍历

 

int ans = 0;

for (int i = 0; i < m; i++) {

    for (int j = 0; j < n; j++) {

        // 只从值为 1 的位置开始找,因为题目说线段从 1 开始

        if (grid[i][j] != 1) {

            continue;

        }

        // 计算从 (i,j) 出发,四个方向理论上能走的最大长度(走到边界的长度)

        int maxs[4] = {m - i, j + 1, i + 1, n - j}; 

 

        for (int k = 0; k < 4; k++)

            // 优化:如果理论长度都没当前 ans 大,没必要递归,跳过

            if (maxs[k] > ans) {

                // 从 (i,j) 出发,第 k 个方向,允许转弯(can_turn=true),第一个要找的 target 是 2 

                ans = max(ans, dfs(i, j, k, true, 2) + 1);

            }

        }

    }

}

return ans;

遍历整个矩阵 ,找到所有值为 1 的位置,然后对每个 1 的位置,尝试四个对角方向出发去探索最长 V 形线段,不断更新  ans (记录全局最长长度 )

auto dfs = [&](this auto&& dfs, int i, int j, int k, bool can_turn, int target) -> int

{

    // ... 函数体

};

 

递归lambda的写法,显式捕获当前类的  this  指针,在 Lambda 内部访问类的成员。

用function包装写也行

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

flume监控文件写入 Kafka 实战:解耦应用与消息队列的最佳实践

flume监控文件写入 Kafka 实战&#xff1a;解耦应用与消息队列的最佳实践 在日志采集场景中&#xff0c;直接让应用程序通过 log4j2 写入 Kafka 会导致应用与 Kafka 强耦合&#xff08;如 Kafka 故障可能影响应用运行&#xff09;。更优的方案是&#xff1a;应用程序将日志写入…

从浏览器无法访问到Docker容器的 FastAPI 服务地址【宿主机浏览器和容器不在同一个网络层面:端口映射】

文章目录1. 问题根源&#xff1a;Docker 网络模型2. 解决方案&#xff1a;端口映射&#xff08;Port Mapping&#xff09;方法 1&#xff1a;重新运行容器并添加端口映射&#xff08;推荐&#xff09;方法 2&#xff1a;获取宿主机的 IP 进行访问&#xff08;特定情况&#xff…

线性代数中矩阵等价与离散数学中关系的闭包之间的关联

最近在重温线性代数时&#xff0c;学到矩阵的等价的定义及其性质&#xff0c;发现其性质与离散数学中关系的闭包所要满足的性质非常相似&#xff0c;不由的让人不怀疑这二者之间存在某种关联&#xff0c;从而引发以下的思考&#xff1a;从deepseek的回答中我明白了矩阵的等价其…

从MyJUnit反思Java项目的工程实践(版本控制篇)

从 MyJUnit 反思Java项目的工程实践(版本控制篇) 参考资料 deepseekgithub copilotCSDN-Git代码管理工作流程&#xff1a;GitFlow详解Conventional Commits手册封面来自 qwen-image 遵循 git flow 分支管理模型 Git Flow 是一种围绕项目发布的核心分支模型, 它规定了不同的开发…

小工具推荐

小工具 ​ 平时不太喜欢去搜罗一些好用的工具&#xff0c;但是看到自己感兴趣的还是会记下来&#xff0c;有的是github上的开源项目&#xff0c;有的是一些直接在线的工具。主要是除了工作时间也不知道去干点什么&#xff0c;或者是和朋友玩玩游戏&#xff0c;或者是city walk…

【js】加密库sha.js 严重漏洞速查

前言sha.js 是 JavaScript 生态里最常用的轻量级加密库。它由 Browserify 社区维护&#xff0c;体积不足 20 KB&#xff0c;却实现了 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 全系列算法&#xff0c;是 crypto-browserify、webpack、web3.js 等数百个流行包的“根依赖”。而…

FPGA入门学习路径

FPGA入门学习路径 专业基础 数电&#xff08;数字电路基础-CSDN博客&#xff09; 语法 Verilog&#xff08;Verilog硬件描述语言-CSDN博客&#xff09; VHDL&#xff08;VHDL硬件描述语言-CSDN博客&#xff09; FPGA开发流程 常用接口设计 学习目的&#xff1a;通过简单…

HTML响应式设计的颜色选择器,适配各种屏幕尺寸

颜色选择器 响应式设计的颜色选择器&#xff0c;适配各种屏幕尺寸 支持色相滑块和RGB数值两种调色方式 点击颜色值或复制按钮即可复制十六进制颜色代码 自动根据背景色调整文字颜色确保可读性 包含复制成功提示动画效果 现代化UI设计&#xff0c;采用圆角、阴影和渐变背景 完全…

ChatGPT登录不进怎么办?

ChatGPT登录不进的核心原因分类ChatGPT登录失败并非单一问题导致&#xff0c;通常与网络环境、账号状态、设备设置及平台限制相关&#xff0c;不同场景下的故障表现与诱因存在明显差异&#xff0c;可分为以下四类&#xff1a;网络连接与地域限制&#xff1a;ChatGPT对访问地域有…

【ConcurrentHashMap】实现原理和HashMap、Redis哈希的区别

【ConcurrentHashMap】实现原理和HashMap、Redis哈希的区别【一】核心思想【1】HashMap​&#xff08;1&#xff09;概括&#xff08;2&#xff09;&#x1f680;线程不安全的场景和原因1-场景一&#xff1a;Put 操作导致的数据覆盖/丢失 (Lost Update)​​2-场景二&#xff1a…

Android 中使用开源库 ZXing 生成二维码图片

在 Android 中生成二维码是一个比较常见的功能&#xff0c;可以使用开源库 ZXing&#xff08;Zebra Crossing&#xff09;库来实现&#xff0c;这是一个非常流行的二维码生成和扫描库。 1、添加依赖库 在 app/build.gradle.kt 中添加依赖库。 dependencies { ......implementat…

vue 如何使用 vxe-table 来实现跨表拖拽,多表联动互相拖拽数据

vue 如何使用 vxe-table 来实现跨表拖拽&#xff0c;多表联动互相拖拽数据 row-drag-config.isCrossTableDrag 启用跨表格、多表格互相拖拽&#xff1b;跨表拖拽需要确保数据主键不重复&#xff0c;通过 row-config.keyField 指定主键字段名 查看官网&#xff1a;https://vxe…

微生产力革命:AI解决生活小任务分享会

微生产力革命的概念微生产力革命指利用AI技术高效解决日常琐碎任务&#xff0c;释放时间与精力。其核心在于将重复性、低价值的事务自动化&#xff0c;聚焦创造性或高价值活动。AI解决生活小任务的典型场景健康管理 AI健身助手可定制个性化训练计划&#xff0c;通过摄像头实时纠…

标量、向量、矩阵和张量的区别

注&#xff1a;本文为 “标量、向量、矩阵和张量的区别” 相关合辑。 英文引文&#xff0c;机翻未校。 如有内容异常&#xff0c;请看原文。 Difference Between Scalar, Vector, Matrix and Tensor 标量、向量、矩阵和张量的区别 Last Updated : 06 Aug, 2025 In the conte…

VScode,设置自动保存

在搜索框输入“autoSave”或VSCode提供以下自动保存选项&#xff1a; 在搜索框输入“autoSave” Off&#xff1a;禁用自动保存。 On Focus Change&#xff1a;当您将焦点从编辑器移开时自动保存。 On Window Change&#xff1a;当您切换窗口选项卡或编辑器时自动保存。 After D…

2025.8.27链表_链表逆置

链表中的指针只是用来标记&#xff0c;具体连接方式&#xff0c;是按照node.next链接。JAVA中头节点存东西&#xff0c;不是空的。核心原理&#xff1a;Java 的参数传递是"值传递"&#xff0c;但对象引用是"值传递引用"也就是传过来了ListNode head。headh…

ssc37x平台的音频应用demo

//ao_test.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include

PPT处理控件Aspose.Slides教程:在.NET中开发SVG到EMF的转换器

SVG和EMF都是基于矢量的格式。许多传统的 CAD 和报告工具仍然倾向于使用 EMF 文件格式&#xff0c;因为它具有更广泛的兼容性。如果您正在开发一个 .NET 项目&#xff0c;并希望实现自动化&#xff0c;使 SVG 到 EMF 的转换变得轻松便捷。Aspose.Slides for .NET是一个功能强大…

深入理解HTTP:请求、响应与状态码解析

深入理解HTTP&#xff1a;请求、响应与状态码解析一&#xff1a;概述二&#xff1a;协议版本三&#xff1a;协议详解1&#xff09;请求报文2&#xff09;响应报文四&#xff1a;状态码1&#xff09;1xx&#xff1a;信息状态码2&#xff09;2xx&#xff1a;成功状态码3&#xff…

浏览器输入网址回车后,访问网页全流程解析!

你在地址栏敲下 https://baidu.com.com 并回车&#xff0c;几百毫秒内发生了很多事&#xff1a;浏览器先想“这个域名的 IP 我记得吗”&#xff0c;接着去找 DNS&#xff1b;建立连接时还要握个手&#xff08;TCP/QUIC&#xff09;顺便打个招呼&#xff08;TLS 证书校验、ALPN …