【Leetcode】十八、动态规划:不同路径 + 全1的最大正方形

news2024/9/24 0:11:36

文章目录

  • 1、动态规划
  • 2、leetcode509:斐波那契数列
  • 3、leetcode62:不同路径
  • 4、leetcode121:买卖股票的最佳时机
  • 5、leetcode70:爬楼梯
  • 6、leetcode279:完全平方数
  • 7、leetcode221:最大正方形

1、动态规划

只能向下、向右的走,从图中左上角走到右下角,有几条路径
在这里插入图片描述因为只能向下、向右走,所以从起始点走到点(R,C),路径数等于,以起始点到点(R,C)为对角线的矩形里,到点(R,C)左侧点的路径数 + 到点(R,C)上边点的路径数 (动态规划的方程式)

// 动态规划的方程式
[RC] = [R - 1][C] + [R][C - 1]

在这里插入图片描述

有些类似斐波那契数列了,起始点就是[0][0] (动态规划的初始状态),那递归终止的条件,就是其左侧点或者上边点不存在,此时,到它的路径只有一条,return 1,一直算到点(R,C)(动态规划的终止状态)。以上,动态规划的三要素:

  • 动态规划的方程式
  • 动态规划的初始状态
  • 动态规划的终止状态

从起始状态(0,0),到终止状态(R,C),中间每个格子的值(到达它的路径数),都会算出来,这些中间结果,可存入一个数组,这题可用二维数组存。动态规划可用来干:

  • 1)计数:有多少种方式或路径,如上面从左上角到右下角有多少路径
  • 2)求最值:从左上角到右下角路径的最大数字和,每个数字不等,代表权重,求最长路径或最小路径
  • 3)求存在性:是否存在某个可能,可以从A走到B

动态规划的分类:

  • 自底向上:从最小的子问题开始,逐步计算出所有可能的状态,直到解决原问题

  • 自顶向下:通过递归地方式,从原问题开始,依次分解为更小的子问题,通常需要记忆化搜索(Memoization)来保存已经计算过的结果,避免重复计算

在这里插入图片描述

2、leetcode509:斐波那契数列

在这里插入图片描述

不再递归了,根据方程式,步步为营,从F(2)一路计算到F(n),并把每个中间值存入数组中,最后返回数组的第n个元素即可

public class P509Two {
    public int recursion(int n) {
        //F(0)和F(1)
        if (n < 2) {
            return n == 0 ? 0 : 1;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;  //F(1)
        // 根据方程式,计算每个值,存入数组,从F(2)一路计算到F(5)
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

3、leetcode62:不同路径

在这里插入图片描述

前面已经分析过了,这儿的方程式为:F(m,n)= F(m - 1,n)+ F(m,n - 1),初始状态为(1,1),终止状态为(m,n)


public class P62 {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        dp[0][0] = 1;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
            	// 如果是边缘,x轴或者y轴,则直接赋值1,因为只有一条路可达,其余按方程式赋值
                if (i == 0 || j == 0) {
                    dp[i][j] = 1;
                } else {
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];
    }
}

红圈里的这些,x轴或者y轴上的,到达他们的路径只有一条,因此直接赋值1,别用方程式去计算,会导致数组下标越界。除了这些点,其余按方程式赋值,最后返回(m-1,n-1)位置的值即可。
在这里插入图片描述

两道题,给我的个人感觉是,动态规划,就是从初始状态开始,根据方程式,步步为营,经过一个个中间状态的值,到达终止状态 ,最后,如果你需要存储这些中间状态值,一般用数组存储,因为其访问数据的时间复杂度为O(1)。

4、leetcode121:买卖股票的最佳时机

在这里插入图片描述

这题,本质就是求数组后面元素与前面元素的差值的最大值,两层for循环,默认返回为0,遇到最大的值就覆盖,即可:

public class P121 {
    public int maxProfit(int[] prices) {
        if (null == prices || prices.length < 2) {
            return 0;
        }
        int result = 0;
        for (int i = 0; i < prices.length - 1; i++) {
        	// 注意内层循环,最快第二天才能卖出,因此,这里是i+1开始
            for (int j = i + 1; j < prices.length; j++) {
                result = Math.max((prices[j] - prices[i]), result);
            }
        }
        return result;
    }
}

优化下:遍历数组,更新前 i 天的最低买入成本,同时更新前i天的最高利润(第i天与前面i-1天最低价的差值,然后不停覆盖这个差值,取最大值)

在这里插入图片描述

public class P121 {
    public int maxProfit(int[] prices) {
        if (null == prices || prices.length < 2) {
            return 0;
        }
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = 0;
        for (int price : prices) {
            minPrice = Math.min(minPrice, price);
            maxProfit = Math.max(maxProfit, price - minPrice);
        }
        return maxProfit;
    }
}

5、leetcode70:爬楼梯

在这里插入图片描述
参考上面62题不同路径的思想:

  • 62题:到(m,n)的路径数 = 到(m,n)上方点的路径数 + 到(m,n)左侧点的路径数,因为规定了只能向下、向右移动
  • 本题:到n阶的路径数 = 到n - 1阶的路径数 + 到 n - 2阶的路径数,因为一次只能走一个或者两个台阶

切入点:动态规划要经过状态转移,那就该想一下,题中要求的状态,怎么可以由上一步到达

由此,动态规划方程式为:

f(n) = f(n - 1) + f(n - 2)

代码实现:

public class P70 {
    public int climbStairs(int n) {
        if (n <= 0) {
            return 0;
        }
        // f(x-1)
        int pre = 1;
        // f(x-2)
        int prePre = 0;
        int result = 1;
        for (int i = 1; i <= n ; i++) {
            result = pre + prePre;
            // 状态转移,往前走一步,f(x-2)变成了新的f(x-1),f(x-1)变成了f(x)
            prePre = pre;
            pre = result;
        }
        return result;
    }
}

6、leetcode279:完全平方数

在这里插入图片描述
思路一:暴力解法

在这里插入图片描述

根据四平方和定理,这题返回的结果肯定是1、2、3、4里的一个。那我找:n是否能由1个平方数搞出来,不行就看是否能由2个平方数搞出来,最多到4,封顶了就。因为这题求的是最少的数量,别说n = 1 + 1 + 1 + …… + 1。借助以下四条数学规律:
在这里插入图片描述

实现:

public class P279 {
    public int numSquares(int n) {
        // 消除4的因子
        while (n % 4 == 0) {
            n = n / 4;
        }
        // %8 == 7,一定是4
        if (n % 8 == 7) {
            return 4;
        }
        // 找a和b两个数,使得n = a^2 + b^2,且a和b这些数必然落在区间 [1,根号n]之间
        for (int a = 0; a * a <= n; a++) {
            int b = (int) Math.sqrt(n - a * a);
            if (a * a + b * b == n) {
                // 找到a,b了,如果a或者b是0,说明a^2 = n或者b^2 = n,返回1,反之,返回2
                return (a > 0 && b > 0) ? 2 : 1;
            }
        }
        // 不是1,也不是2,那就是3
        return 3;
    }
}

思路二:动态规划

用几个数的平方的和表示数字n,这几个平方数一定在[1,根号n] 之间,因为根号n的平方就是n了。从1到根号n的范围,遍历,假设遍历到了数字 j,此时剩下 n - j * j ,n - j * j 的平方数字的数量假设为f(n - j * j ),那f(n)就是这个值 + 1,状态转移方程:

f(n) = f(n - j * j ) + 1

当然,这题找最小数量,因此,取的是[1,根号n],最小的平方数的数量,代码实现:

public class P279 {
     public int numSquares(int n) {
        int[] resultArr = new int[n + 1];
        // 算从1到n,每个数的平方数的数量
        for (int i = 1; i <= n; i++) {
            int minn = Integer.MAX_VALUE;
            // j * j <= i,即从1到根号n的范围
            for (int j = 1; j * j <= i; j++) {
                minn = Math.min(minn, resultArr[i - j * j]);
            }
            resultArr[i] = minn + 1;
        }
        return resultArr[n];
    }
}

7、leetcode221:最大正方形

在这里插入图片描述

dp(i,j) 表示以 (i,j) 为右下角,且只包含 1 的正方形的边长最大值,那这个dp值,应该取决于其左边、上边、右上方三个点的dp值,如下图:

在这里插入图片描述

红色方框所在的点(2,3),其dp值,取决于黄色方框里的三个点的dp值,且是像短板水桶一样,全是1的正方形的最大边长,得看这三个点dp的最小值,得出状态转移方程式为:

dp(i, j) = min ( dp(i - 1, j), dp(i, j - 1), dp(i - 1, j - 1) ) + 1

代码实现:

public class P221 {
    public int maximalSquare(char[][] matrix) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return 0;
        }
        // 最大边长
        int maxSide = 0;
        // 矩阵行列数
        int row = matrix.length;
        int col = matrix[0].length;
        int[][] dp = new int[row][col];
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (matrix[i][j] == '0') {
                    // 值为0,则不存在全为1的正方形,int默认值就是0,这里不赋值也行
                    dp[i][j] = 0;
                } else {
                    // 在x轴或者y轴边上,那以其为右下角的正方形,就只能是自己那一块,dp = 1
                    if (i == 0 || j == 0) {
                        dp[i][j] = 1;
                    } else {
                        // 否则就走正常的状态转移方程
                        dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                    }
                }
                // 求整个矩阵中,每个点的dp的最大值
                maxSide = Math.max(maxSide, dp[i][j]);

            }
        }
        return maxSide * maxSide;
    }
}

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

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

相关文章

CTFSHOW 萌新 web5 解题思路和方法

点击题目链接&#xff0c;发现页面代码&#xff0c;根据最后一行的提示当id1000时返回flag值&#xff0c;但是前面if判断intval(id)的值不得超过999&#xff0c;故需要对其进行绕过。 我们发现题目中相比前几题中过滤条件更为严格&#xff0c;但是没有过滤取反运算符。此时我们…

matlab 绘制参数方程

matlab 绘制参数方程 绘制参数方程绘制结果 绘制参数方程 clc; clear; close all;axis_length 100;% 定义参数t的范围 t 0:0.01:100;% 计算x和y的值 x t.^2 1; y 4*t - t.^2;% 绘制函数图像 plot(x, y); xlabel(x); ylabel(y); title(Plot of the curve xt^21, y4t-t^2…

运维朋友最喜欢的一集:trzsz-ssh!!【送源码】

软件介绍 trzsz-ssh&#xff08;tssh&#xff09;是一个替代openssh的SSH客户端软件&#xff0c;支持trzsz、批量登录、密码记忆、zmodem等功能。可实现方便的本地与远程服务器文件传输&#xff0c;支持多系统跨平台运行&#xff0c;提供良好的交互体验和进度显示。优势包括tmu…

普发Pfeiffer真空TSH071TSU261TSH521泵站电路图安装操作使用说明

普发Pfeiffer真空TSH071TSU261TSH521泵站电路图安装操作使用说明

0724, 大型补作业现场

sock编程 struct sockaddr struct sockaddr_in --> struct in_addr struct hostent htonl() htons() ntohl() ntohs() int inet_aton(const char* cp,struct in_addr * inp); in_addr_t inet_addr(const char* cp); const char* inet_ntop…

深入理解算数表达式求值:后缀表达式的转换与计算

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd;没人会嘲笑竭尽全力的人&#xff01; 前…

软件渗透测试包括的内容和作用简析

在当今信息技术迅速发展的时代&#xff0c;软件安全已成为企业和用户关注的重中之重。尤其是渗透测试作为一种专业的安全测试方法&#xff0c;日益受到企业们的重视。   软件渗透测试是一种模拟恶意攻击者的方式&#xff0c;对软件及其相关系统进行评估&#xff0c;以发现可能…

html基础及python web开发

1.标签 ①p标签 段落标签&#xff0c;分隔段与段。 <p>...</p> ②h标签 标题标签h1-6&#xff0c;大小依次减小 <h1>...</h1> <h2>...</h2> <h3>...</h3> <h4>...</h4> <h5>...</h5> <h6>.…

数据结构的概念和术语

目录 一.前言 二.数据结构的基本概念 三.数据结构的术语 一.前言 数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科。数据结构的基本数据结构包括两部分&#xff0c;线性结构跟非线性结构。 二.数据结构的基本概念 数据结构主要包括…

MarkTool集合篇

MarkTool目前包含以下几种工具 1、TCP客户端 2、TCP服务端 3、UDP客户端 4、Web客户端 5、Web服务端 6、串口网口 7、PLC 8、获取本机设备 9、Log 10、密钥 11、系统设置 11-1、基本设置 11-2、角色设置 11-3、用户设置 11-4、log记录 开启软件需要找我解密&#…

怎样做好仓库管理工作?如何利用仓库管理系统进行有效管理?

我前前后后跑遍了十几家仓储设备公司&#xff0c;跟那些制造业的朋友们聊了个痛快&#xff0c;从他们那儿学到了不少仓库管理的实践方法。 回来自己整理了一套仓库管理更高效的实用方法&#xff0c;现在就来跟大家伙儿聊聊仓库管理中那些常见问题&#xff0c;以及我是怎么琢磨…

(前缀和) LeetCode 238. 除自身以外数组的乘积

一. 题目描述 原题链接 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&…

HarmonyOS网络请求的简单用法,HttpUtil简单封装

请求网络获取数据 点击按钮发送一个post请求&#xff0c;发送一条string由于此处的返回result.data本身就是一个string&#xff0c;因此不需要转换类型 Button(请求网络).margin({ top: 10 }).fontSize(24).fontWeight(FontWeight.Bold).onClick(() > {httpRequestPost(http…

算法从零到精通 (一) ~ 快慢双指针

1. 前言 快慢双指针是一种常用的算法技巧&#xff0c;通常用于解决涉及链表或数组的问题。它的基本思想是使用两个指针&#xff0c;一个移动速度快&#xff08;快指针&#xff09;&#xff0c;一个移动速度慢&#xff08;慢指针&#xff09;&#xff0c;来解决特定的问题。这两…

【高可用】利用AOP实现数据库读写分离

最近项目中需要做【高可用】数据库读写分离相关的需求&#xff0c;特地整理了下关于读写分离的相关知识。项目中采用4台数据库&#xff1a;1个master&#xff0c;2个slave&#xff0c;1个readOnly&#xff0c;其中master数据库会自动定时同步到readOnly节点。可以通过中间件(Sh…

Mysql —— 事务

目录 什么是事务&#xff1f; 两种方式实现事务&#xff1a; 方法一 方法二&#xff1a; 事务四大特性(简称ACID) 并发事务问题&#xff08;面试题&#xff09; 事务隔离级别 什么是事务&#xff1f; 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff…

跨域浏览器解决前端跨域问题

1.问题背景 这是一种属于非主流的解决跨域的方案&#xff0c;但是也是可以正常使用而且比较简单的。如果需要使用主流的解决前端跨域方案&#xff0c;请参考这篇文章。 我这边其实是优先建议大家使用主流的跨域方案&#xff0c;如果主流的实在不行&#xff0c;那么就使用跨域…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 图像物体的边界(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线…

scratch绘制十个圆 2024年6月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch绘制十个圆 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、实现流程 1、案例分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、…

css气泡背景特效

css气泡背景特效https://www.bootstrapmb.com/item/14879 要创建一个CSS气泡背景特效&#xff0c;你可以使用CSS的伪元素&#xff08;:before 和 :after&#xff09;、border-radius 属性来创建圆形或椭圆形的“气泡”&#xff0c;以及background 和 animation 属性来设置背景…