【力扣分模块练习】动态规划 + 排序(如何忽略一个维度的动归 / LIS算法)

如果碰到一种题目,有两个变量,解题时需要同时维护两个变量尽可能小的增加(增加幅度尽可能小),就需要用到这种动归+排序的方法。

基准方法是用DP计算一个序列的最长递增子序列。

300. 最长递增子序列
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4

题解:
本题的核心是不好想dp[i]的意义。
dp[i]其实是以i角标结尾的子序列的最大递增子序列的长度。所以只需要遍历i之前的数字,如果某个数j小于i,则只需要将dp[j]+1(选中i这个数,自然序列加一了)即可。找到满足条件的最大的dp[j],就可以算出最终的dp[i]。
最后结果res就是完全算出来dp[i]之后,其中最大的一个数。

class Solution {
    
    
public:
	int lengthOfLIS(vector<int>& nums) {
    
    
		int n = nums.size();
		//dp为角标为i时,最长递增序列的长度
		vector<int> dp(n, 1); 
		int res = 0;
		for (int i = 0; i < n; i++)
		{
    
    	//j不超过i的位置,因为j是i之前所有的数
			for (int j = 0; j < i; j++)
			{
    
    
				if (nums[j] < nums[i])
				{
    
    
					dp[i] = max(dp[i], dp[j] + 1);
				}
			}
			res = max(res, dp[i]); //res是全部dp中最大的一个
		}

		return res;
	}
};

354. 俄罗斯套娃信封问题
给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
说明:
不允许旋转信封。

示例:
输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。

题解:
本题是上题的进阶版。难点在于如何既保证宽度上升的慢,又保证高度上升的慢的。如果单纯用排序+贪心的方法,如下这个案例会出错:
[[2,100],[3,200],[4,300],[5,500],[5,400],[5,250],[6,370],[6,360],[7,380]],经排序后,[4,300]会被优先选中,一下子把高度撑得太大,后面就只能选400啥的,损失了好几个。
如果做过上题300题,就可以想到最大递增子序列的问题。这样的话,我们只需要先按照第一维度递增(这样就保证了第一维度绝不会出错),第二维度递减(这样可以为最长递增子序列创造他条件)。这样算出来的res是不会出错的。

class Solution {
    
    
public:
	int maxEnvelopes(vector<vector<int>>& env) {
    
    
		int n = env.size();
		sort(env.begin(), env.end(), [&](vector<int> a, vector<int> b) {
    
    
			if (a[0] != b[0])
				return a[0] < b[0];
			else
				return a[1] > b[1];
		});

		//宽升序,高降序,忽略宽维度,对高使用最长增子序长度的dp算法LIS
		vector<int> dp(n, 1);
		int res = 0;
		//表示以i角标结尾的序列的最长增子序的长度
		for (int i = 0; i < n; i++)
		{
    
    
			for (int j = 0; j < i; j++)
			{
    
    
				if (env[i][1] > env[j][1])
					dp[i] = max(dp[i], dp[j] + 1);
			}
			res = max(res, dp[i]);
		}

		return res;
	}
};

猜你喜欢

转载自blog.csdn.net/abyss_miracle/article/details/114368580
今日推荐