一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
前言
每日一题,轻松解题
每日一题为刷题系列 每日刷一题LeetCode题,并且对题目进行分析,分享思路。
正文
:最大子矩阵
难度:困难
题目要求:
给定一个正整数、负整数和 0 组成的 N × M 矩阵,编写代码找出元素总和最大的子矩阵。
返回一个数组 [r1, c1, r2, c2],其中 r1, c1 分别代表子矩阵左上角的行号和列号,r2, c2 分别代表右下角的行号和列号。若有多个满足条件的子矩阵,返回任意一个均可。
举个例子
输入: [ [-1,0],
[0,-1]
]
输出: [0,1,0,1]
解释: 输入中标粗的元素即为输出所表示的矩阵
:解题
方法一 :动态规划(DP)
动态规划(DP)
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
解题思路:
-
将二维数组打平,再求最大连续和。
-
这里使用了三个函数去处理取值:
-
dp:接收一个数组,返回该数组的最大连续和,并返回这个和的起止坐标。
-
countArr:将一个二维数组打平,每一列进行累加,变成一个数组。
-
循环:遍历循环所有矩阵,拿到每个矩阵的最大值。
-
最后返回最大的那个的起止坐标。
编辑代码:
function getMaxMatrix(matrix: number[][]) {
/**
* 计算平面数组的最大连续和,并返回该和的起止坐标
* @param nums
* @returns
*/
const dp = (nums: number[]): {
val: number,
index: number[]
} => {
const len = nums.length
const dp = [...nums]
const length = new Array(len).fill(1)
for(let i = 1; i < len; i++) {
if(dp[i - 1] + dp[i] > dp[i]) {
dp[i] = dp[i - 1] + dp[i]
length[i] += length[i - 1]
}
}
const max = Math.max(...dp)
let k: number
for(let i = 0; i < len; i++) {
if(dp[i] === max) {
k = i
break
}
}
return {
val: dp[k!],
index: [k! - length[k!] + 1, k!]
}
}
/**
* 将二维数组压平,转化为一维数组
* @param matrix
* @returns
*/
const countArr = (matrix: number[][]): number[] => {
if(matrix.length === 1) return matrix[0]
let arr = new Array(matrix[0].length).fill(0)
for(let row = 0; row < matrix.length; row++) {
for(let col = 0; col < matrix[0].length; col++) {
arr[col] += matrix[row][col]
}
}
return arr
}
const len = matrix.length
const map = new Map<number, number[]>()
const set = []
for(let i = 0; i < len; i++) {
for(let j = 0; j <= i; j++) {
// 二维转一维
const tmp = dp(countArr(matrix.slice(j, i+1)))
map.set(tmp.val, [j, tmp.index[0], i, tmp.index[1]])
set.push(tmp.val)
}
}
const max = Math.max(...set)
let result: number[]
map.forEach((item, key) => {
if(key === max) result = item
})
return result!
};
总结
无论做什么分析最重要,其中我们分析了题目,分析了解题思路,其实在分析完解题思路后,代码其实就是很简单的事情了,养成习惯,无论做什么之前,都要进行分析,这样有助于你更快更好的完成这件事。