代码随想录算法训练营第56天 | 300.最长递增子序列 674.最长连续递增序列 718.最长重复子数组

最长递增子序列

Alt
这里dp数组的定义比较难想。dp[i] 表示 i 之前的序列中以 nums[i] 结尾的最长递增子序列长度,只有这样才能实现状态递推。对于dp数组初始化,所有下标位置都应该初始化为1。

class Solution{
public:
	int lengthOfLIS(vector<int>& nums) {
		vector<int> dp(nums.size(), 1);
		int result = 1;
		for(int i = 1; i < nums.size(); i++) {
			for(int j = 0; j < i; j++) {
				if(nums[i] > nums[j])
				dp[i] = max(dp[i], dp[j] + 1);
			}
			if(dp[i] > result){  // 维护dp数组中的最大值作为最终结果,每一个下标都有可能作为子序列的结尾
				result = dp[i];
			}
		}
		return result;
	}
};

最长连续递增序列

Alt
这道题不同于上一道题,要求必须是连续子序列,这样当前状态只与上一状态有关,而不连续子序列中的状态则与 0 ~ i-1 的状态都相关。

class Solution {
public:
	int findLengthOfLCIS(vector<int>& nums) {
		// dp[i]表示i之前的序列中以nums[i]结尾的连续递增子序列的最长长度
		vector<int> dp(nums.size(), 1);
		int result = 1;
		for(int i = 1; i < nums.size(); i++) {
			if(nums[i] > nums[i - 1])
			dp[i] = dp[i - 1] + 1;
			if(dp[i] > result)  result = dp[i];
		}
		return result;
	}
};

其实这道题贪心也能解,而且具有O(1)的复杂度。

class Solution {
public:
	int findLengthOfLCIS(vector<int>& nums) {
		int count = 1;
		int result = 1;
		for(int i = 1; i < nums.size(); i++) {
			if(nums[i] > nums[i - 1]){  // 局部连续递增,count加一
				count++;
			}
			else{
				count = 1;  // 连续递增结束,count = 1
			}
			if(count > result)  result = count;  // 局部最优解取最大值,得到全局最优
		}
		return result;
	}
};

最长重复子数组

Alt
使用一个二维dp数组就可以覆盖所有的数组比较情况。dp[i][j] 表示数组1以 i-1 下标结尾的子数组与数组2以 j-1 下标结尾的子数组中最长的公共子数组长度。注意:这里之所以表示i-1和j-1下标是为了初始化的方便,代码可以更加简洁,所以就在dp数组含义的定义上绕了一下。
如果定义i-1,那么在遍历递推时肯定要从 i=1, j=1 开始,dp[0][j]和dp[i][0]实际实际上都是没有意义的。只是为了后面递推结果的正确,假设nums[i - 1] == nums2[0],则 dp[i][1] = dp[i - 1][0] + 1,这里dp[i - 1][0] 只能为0。

class Solution{
public:
	int findLength(vector<int>& nums1, vector<int>& nums2) {
		vector<vector<int>> dp(nums1.size() + 1, vector<int>(nums2.size() + 1, 0));
		int result = 0;
		for(int i = 1; i <= nums1.size(); i++) {
			for(int j = 1; j <= nums2.size(); j++) {
				if(nums1[i - 1] == nums2[j - 1]){
					dp[i][j] = dp[i - 1][j - 1] + 1;
				}
				if(result < dp[i][j]){
					result = dp[i][j];
				}
			}
		}
		return result;
	}
};

如果dp数组的含义就是直接表示以 i 或 j 结尾的子数组之间的数值,那么需要进行额外的初始化,而且在遍历递推时仍然要从0开始,因为要统计最大值求得最终结果,需要包含 dp[i][0] 和 dp[0][j]。要额外避免数组越界。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值