200215题(最长上升子串(腾讯(dp问题或贪心)))

在这里插入图片描述
法1:dp,时间复杂度O(n2),空间复杂度O(n)
定义dp[i]的值代表以nums[i]结尾的最长子序列长度;
初始化,dp[i] 所有元素置1,含义是每个元素都至少可以单独成为子序列,此时长度都为1;
如果nums[i]严格大于[0,i)中的某个数j,那么说明nums[i]就可以在dp[j]的基础上形成一个长度为dp[j]+1的上升子序列;
因此,得到递推关系:if(nums[j]<nums[i]) dp[i]=max(dp[i],dp[j]+1);

//dp[i]的值代表以nums[i]结尾的最长子序列长度
class Solution {
public:
	int lengthOfLIS(vector<int>& nums) {
		if (nums.size() == 0)return 0;
		vector<int>dp(nums.size());
		//初始化,dp[i] 所有元素置1,含义是每个元素都至少可以单独成为子序列,此时长度都为1
		//如果nums[i]严格大于[0,i)中的某个数j,那么说明nums[i]就可以在dp[j]的基础上形成一个长度为dp[j]+1的上升子序列
		//因此,得到递推关系:if(nums[j]<nums[i]) dp[i]=max(dp[i],dp[j]+1);
		for (int i = 0; i < nums.size(); i++)
			dp[i] = 1;
		int max_len = 1;
		for (int i = 0; i < nums.size(); i++)
		{

			for (int j = 0; j < i; j++)//j在[0,i)中
			{
				if (nums[j] < nums[i])
					dp[i] = max(dp[i], dp[j] + 1);
			}
			max_len = max(max_len, dp[i]);
		}
		return max_len;
	}
};

法2:贪心算法(动态规划 + 二分查找)
时间复杂度O(logn),空间复杂度O(n)

建立一个tails数组,res表示当前的上升序列最大长度
初始化:

int res = 1;
tails[0] = nums[0];

思路:每一次来一个新的数num,在tail数组中的[0,res-1]区间找和num相等的数或第一个比num大的数,并记录下标;如果在该区间中找到了,那么将那个数替换成num,如果没有找到,则把num赋值给tail[res],然后res++,体现了贪心的思想。

在tail数组中的[0,res-1]区间找和num相等的数或第一个比num大的数时,可以使用二分法,而二分法的时间复杂度为O(logn);

感慨一下:这个代码改了好久才写出来,真不容易!
这里二分法使用了leetcode第35题的代码。

class Solution {
public:
	int lengthOfLIS(vector<int>& nums) {
		if (nums.size() == 0)return 0;
		vector<int>tails(nums.size(), 0);

		int res = 1;
		tails[0] = nums[0];

		for (int i = 1; i < nums.size(); i++)
		{
			if (BinarySearch(tails, 0, res-1, nums[i]) == res)
				res++;
		}
		return res;
	}

	int BinarySearch(vector<int>&tails, int left, int right, int target) {
		//二分法在升序数组中寻找和target相等的数的下标或第一个比target大的数的下标(如果有)
		//这里就是leetcode35题的写法!!!	

		while (left <= right)
		{
			int mid = (left + right) / 2;
			if (tails[mid] == target)
				return mid;
			else if (target < tails[mid])
			{
				right = mid - 1;
			}
			else
			{
				left = mid + 1;
			}
		}
		tails[left] = target;//贪心
		return left;
	}
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值