一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
一.题目:
354. 俄罗斯套娃信封问题 给你一个二维整数数组
envelopes,其中envelopes[i] = [wi, hi],表示第i个信封的宽度和高度。
当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算 最多能有多少个 信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
示例 1:
输入:envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出:3
解释:最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。
示例 2:
输入: envelopes = [[1,1],[1,1],[1,1]]
输出: 1
提示:
1 <= envelopes.length <= 105envelopes[i].length == 21 <= wi, hi <= 105
二、思路分析:
首先需要明白解决这道问题的办法,试着把二维数组转化为一维数组的问题,在转化为一维数组之后,我们就利用到了最长递增子序列的思路去求解能够形成多少个俄罗斯套娃信封。基本的思路如下:
-
利用
sort函数将二维数组的问题转化为一维数组的问题,我们首先通过第一个数进行判断,如果第一个数不相等,按照第一个数从小到大排序,如果第一个数相等,按照第二个数从大到小排序,这么做的目的是什么呢,首先通过第一个数排序后我们就能够得到一个相对于第一数递增的序列,然后我们只需要通过数组里面的第二个数进行判断最长子序列即可。 -
如何判断最长递增子序列最常用的方法就是
动态规划,就是通过比较不断地更新最大递增子序列的值然后返回这个最大值即可得出结果,但是这道题目如果采取常规的动态规划框架就会造成超时,所以需要使用二分查找的变体来实现动态规划。
三、代码:
/**
* @param {number[][]} envelopes
* @return {number}
*/
var maxEnvelopes = function (envelopes) {
//边界条件
if(envelopes.length === 1) return 1
//排序,如果第一个数不相等,按照第一个数从小到大排序,如果第一个数相等,按照第二个数从大到小排序,这样做的目的很牛
envelopes.sort((a, b) => {
//前一个数如果不相等按照第一个数进行排序
if (a[0] !== b[0]) return a[0] - b[0]
else return b[1] - a[1]
})
let arr = []
for (let [width, height] of envelopes) {
arr.push(height)
}
function getNum(arr) {
let piles = 0
let top = new Array(arr.length)
for(let i=0 ; i<arr.length ; i++){
let poker = arr[i]
let left = 0, right = piles
while(left<right){
let mid = Math.floor(left + (right-left)/2)
if(top[mid] > poker){
right = mid
}else if(top[mid] < poker){
left = mid+1
}else{
right = mid
}
}
if(left == piles) piles++
top[left] = poker
}
return piles
}
return getNum(arr)
};
四、总结:
这道题目理解起来其实很容易,虽然他是一道困难的题目,但是实现起来确实很难,因为在力扣上提交代码如果是常规的动态规划就会超时,所以需要使用二分查找的变体。所以这道题告诉我们不应该只了解基本框架代码而应该深入地去了解。