算法48:动态规划专练(力扣221:最大正方形面积)

2024-03-07 14:12

本文主要是介绍算法48:动态规划专练(力扣221:最大正方形面积),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目:

在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

示例 1:

输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:4

示例 2:

输入:matrix = [["0","1"],["1","0"]]
输出:1

示例 3:

输入:matrix = [["0"]]
输出:0

我之前写过一篇博客,是利用单调栈计算最大矩形面积的。感兴趣的看一下:算法37:最大矩形面积(力扣84、85题)---单调栈-CSDN博客

而本道题目求的是最大正方形面积,因此,利用单调栈完全可以解决。思路和求最大矩形面积是一样的,下面直接贴出单调栈的代码:

单调栈解法:

package code04.动态规划专项训练02;/***  力扣 221题  最大正方形面积*  https://leetcode.cn/problems/maximal-square/?envType=study-plan-v2&envId=dynamic-programming*/
public class MaximalSquare_03_leetcode221单调栈 {public int maximalSquare(char[][] matrix) {if (matrix == null || matrix.length == 0) {return 0;}int[] dp = new int[matrix[0].length];int res = 0;for (int i = 0; i < matrix.length; i++) {for (int j = 0; j < matrix[i].length; j++) {//数组压缩int cur = matrix[i][j] == '0' ? 0 : Integer.parseInt(String.valueOf(matrix[i][j]));dp[j] = cur == 0 ? 0 : dp[j] + cur;}res = Math.max(res, getMaxValue(dp));}return res;}public int getMaxValue (int[] arr) {int result = 0;int size = arr.length;//自定义栈结构int[] stack = new int[arr.length];int stackSize = 0;for (int i = 0; i < arr.length; i++) {while (stackSize != 0 && arr[stack[stackSize-1]] >= arr[i]) {//当前弹出数的下标int curIndex = stack[--stackSize];//左边第一个比curIndex数组对应数小的下标int leftIndex = stackSize == 0 ? -1 : stack[stackSize -1];//右边第一个比curIndex数组对应数小的下标int rightIndex = i;int width = Math.min(arr[curIndex], rightIndex - leftIndex - 1);result = Math.max(result, width * width);}stack[stackSize++] = i;}//如果还有剩余while (stackSize != 0) {//当前弹出数的下标int curIndex = stack[--stackSize];//左边第一个比curIndex数组对应数小的下标int leftIndex = stackSize == 0 ? -1 : stack[stackSize -1];int width = Math.min(arr[curIndex], size - leftIndex - 1);result = Math.max(result, width * width);}return result;}public static void main(String[] args) {MaximalSquare_03_leetcode221单调栈 ss = new MaximalSquare_03_leetcode221单调栈();char[][] matrix = {{'1','0','1','0','0'},{'1','0','1','1','1'},{'1','1','1','1','1'},{'1','0','0','1','0'}};System.out.println(ss.maximalSquare(matrix));}
}

 

胜率虽然不高,但是只花费了 12毫秒, 还算可以的了。

本章是动态规划专练,因此,不得不说一下动态规划的思路:

1. 我们知道,正方是有4个顶点,并且每条边的边长都是相等的。

2. 本道题规定,如果每个单元格的值为1,那么它最小也可以看成是变成为1的正方形。如果为0,当前单元格就不能算作正方形。

3. 如果只有4个顶点,想要组成最大边长为2的正方形,那么这4个顶点必定全部都为1.  如果以最后一个顶点为正方形的结束点,那么依赖的其他三个点,必定全部不为0.

 

X1X3
X2

1 + Math.min(X1, Math.min(X2, X3))

(依赖左、上、左上3个顶点的最小值)

也就是说,目前看到的这些节点,以当前单元格

结束,那么它的最大边长就是1 + Math.min(X1, Math.min(X2, X3))

为什么要依赖最小值?

因为,X1、X2、X3任何一点为0, 那么以当前单元格为正方形的结束节点,那么它的最大正方形边长就为1. 当然,当前单元格的值必须不为0.

4. 第一行,正方形的边长最大为1; 第一列,最大正方形的边长也为1. 因为正方形边长是需要相等的。

我们根据事例1给的数据进行推导:

第一步:

下标01234
下标010100
11

原始数组为0,

无法参与到正

方形的结束点.

直接取0

前一列为0,

上一列为1.取小。

当前列为1. 

因此, 1 + 0 = 1

1 + 0 = 11 + 0 = 1
21
31

第二步:根据上方规则,类推

下标01234
下标010100
11

0

1

11
211 + 0 = 11 + 1 = 21+ 1 = 21+ 1 = 2
31

第三步:根据上方规则,类推

下标01234
下标010100
11

0

1

11
211222
31001+0 = 10

 目测就知道,最大正方形的边长为2. 面积为 4;

动态规划代码:

package code04.动态规划专项训练02;/*** 力扣 221题  最大正方形面积* https://leetcode.cn/problems/maximal-square/?envType=study-plan-v2&envId=dynamic-programming*/
public class MaximalSquare_03_leetcode221动态规划 {public int maximalSquare(char[][] matrix) {if (matrix == null || matrix.length == 0) {return 0;}int row = matrix.length;int col = matrix[0].length;int[][] dp = new int[row][col];int maxSide = 0;//第一行for (int i = 0; i < col; i++) {dp[0][i] = matrix[0][i] == '0' ? 0 : 1;if (maxSide == 0 && dp[0][i] > 0) {maxSide = 1;}}//第一列for (int i = 0; i < row; i++) {dp[i][0] = matrix[i][0] == '0' ? 0 : 1;if (maxSide == 0 && dp[i][0] > 0) {maxSide = 1;}}for (int index1 = 1; index1 < row; index1++) {for (int index2 = 1; index2 < col; index2++) {if (matrix[index1][index2] == '1') {//左上顶点int p1 = dp[index1 - 1][index2 - 1];//左顶点int p2 = dp[index1][index2 - 1];//上顶点int p3 = dp[index1 - 1][index2];dp[index1][index2] = Math.min(p3, Math.min(p1, p2)) + 1;} else {dp[index1][index2] = 0;}maxSide = Math.max(maxSide, dp[index1][index2]);}}return maxSide * maxSide;}public static void main(String[] args) {MaximalSquare_03_leetcode221动态规划 ss = new MaximalSquare_03_leetcode221动态规划();//char[][] matrix = {{'1', '0', '1', '0', '0'}, {'1', '0', '1', '1', '1'}, {'1', '1', '1', '1', '1'}, {'1', '0', '0', '1', '0'}};//char[][] matrix = {{'0', '1'}, {'1', '0'}};char[][] matrix = {{'0', '1'}};System.out.println(ss.maximalSquare(matrix));}
}

它的确比单调栈更快,效率更高。而且,它的思路更加的简单。

但是,它只能解决正方形的问题,如果是矩形,当前思路都无法解决。因此,他有一定的局限性。

下一道题,同样也是算最大正方形面积的题目。但是,单调栈、本章的动态规划推导思路完全不适用,只能用暴力方法去解决。因此,本道题的暴力方法,也必须得介绍一下。

暴力解法:

1. 遍历全部单元格,找出每个单元格作为正方形顶点的最大边长。

2. 在步骤1找的过程中,是范围内的验证。

暴力解法思路相对简单,只是代码比较复杂

package code04.动态规划专项训练02;/*** 力扣 221题  最大正方形面积* https://leetcode.cn/problems/maximal-square/?envType=study-plan-v2&envId=dynamic-programming* <p>* 基本思路:* 1. 当前列为正方形起点。* 从左往右,推算出最大边长; 从上往下推算出最大边长; 因为是正方形,因此之前两个边长取小* 2. 对这个范围内的所有格子进行为1验证*/
public class MaximalSquare_03_leetcode221暴力解 {public int maximalSquare(char[][] matrix) {if (matrix == null || matrix.length == 0) {return 0;}int row = matrix.length;int col = matrix[0].length;//最大边长int max = 0;for (int i = 0; i < row ; i++) {//当前行的每一列都作为正方形的左上角,即起始点for (int j = 0; j < col; j++) {//当前格子是否为1,为1才可能成为正方形的起始点if (matrix[i][j] == '0') {continue;}//整个二维数组中,重要有1出现,那正方形边长至少为1if (max == 0) {max = 1;}//行边长,列边长,两者取小。因为是正方形int p = Math.min(row - i, col - j);//从i,j开始 到 i+index,j+index 范围内。全部都为1,才能验证通过//start为默认边长,默认边长为1. 因为matrix[i][j] == 1for (int count = 1; count < p; count++) {//斜线if (matrix[i + count][j+count] == '0') {break;}boolean flag = true;// 如果上边行、左边列延伸都不为0;那就继续校验正方形// 内部是否全为1for (int m = 0; m < count; m++) {if (matrix[i + count][j + m] == '0' || matrix[i + m][j + count] == '0') {flag = false;break;}}if (flag) {//默认边长为1, 即当前正方形做顶点为1//count是新增的长度。 count+1 代表正常放边长max = Math.max(max, count + 1);}else {break;}}}}return max * max;}public static void main(String[] args) {MaximalSquare_03_leetcode221暴力解 ss = new MaximalSquare_03_leetcode221暴力解();//char[][] matrix = {{'1', '0', '1', '0', '0'}, {'1', '0', '1', '1', '1'}, {'1', '1', '1', '1', '1'}, {'1', '0', '0', '1', '0'}};char[][] matrix = {{'0', '1'}, {'1', '0'}};System.out.println(ss.maximalSquare(matrix));}
}

因此,本道题使用单调栈、动态规划性能更高。暴力解法,性能低。因为下一道题,只能基于暴力解法完成并优化,因此,不得不提前在此提一下暴力解法。

这篇关于算法48:动态规划专练(力扣221:最大正方形面积)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/783785

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同