300. Longest Increasing Subsequence (Longes Increasing Subsequence, LIS)

Medium difficulty 1382

Given an array of integers  nums , find the length of the longest strictly increasing subsequence.

A subsequence is a sequence derived from an array, deleting (or not deleting) elements in the array without changing the order of the remaining elements. For example, it [3,6,2,7] is [0,3,1,6,2,2,7] a subsequence of an array  .

Example 1:

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

Example 2:

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

Example 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

prompt:

  • 1 <= nums.length <= 2500
  • -104 <= nums[i] <= 104

Advanced:

  • Can you design O(n2) a solution with a time complexity of  ?
  • Can you reduce the time complexity of the algorithm to  O(n log(n)) ?

Basic dynamic programming solution (O(N2)) : When dp[i] records the length of the longest strictly increasing subsequence of the first i digits when the i-th digit is the end, the dynamic transition equation is:

dp[i]=max(dp[j])+1, where 0≤j<i and num[j]<num[i])

That is, when num[i]> num[j], it means that when num[i] is used as the end, it can be larger than the end of dp[j], that is, the length is +1. Compare all the cases where it can be the end to find the maximum dp[i]. During the recording process, compare all dp[i], and the maximum value is the result.

class Solution {
public:
	int lengthOfLIS(vector<int>& nums) {
		vector<int>dp(nums.size(), 1);
		int res = 1;
		for (int i = 1; i < dp.size(); ++i) {
			for (int j = 0; j < i; ++j) {
				if (nums[i] > nums[j])
					dp[i] = max(dp[i], dp[j] + 1);
			}
			res = max(res, dp[i]);
		}
		return res;
	}
};

Through binary search, optimized dynamic programming ((O(NlogN))) : In order to further optimize the time complexity, the meaning of modifying the dp array is that dp[i] represents the longest strictly increasing subsequence in the results of the previous search The minimum value at the end of the queue when the length is i. Therefore, when traversing, you only need to traverse the dp array, compare num[i] with the smallest end of different lengths, and if it is greater than that, the length should be increased by one. Since the dp[i] specified here is the smallest end of length i, the dp array is strictly monotonically increasing (disprove: suppose there is a non-increasing dp[i]> dp[j], i <j, such as dp[2 ] = 8,dp[4] = 5, since the defined dp[4] is the end value of an increasing sequence of length 4, the previous three numbers must be less than 5, so the smallest end of length 2 must also be less than 5. ). Therefore, the position of the dp array smaller than num[i] can be found by binary search, and it can be updated by comparing it with the dp value of the next position. Finally, the size of the dp array is the result.

Note: lower_bound and upper_bound are both binary search algorithms, both of which find the position of the target value. The difference is that lower_bound returns the  first  insertable position, while upper_bound finds the  last  insertable position, for example For [1, 3, 5, 5, 7, 8], when val = 5, the index returned by lower_bound is 2, and the index returned by upper_bound is 4. When val = 4, the index returned by lower_bound is 3, and the index returned by upper_bound is 3.

class Solution {
public:
	int lengthOfLIS(vector<int>& nums) {
		vector<int>dp;
		dp.push_back(INT32_MIN);
		dp.push_back(nums[0]);
		int res = 1;
		for (int i = 1; i < nums.size(); ++i) {
			int index = lower_bound(dp.begin(), dp.end(), nums[i]) - dp.begin();
			//cout << index << ' '<<i<< ' '<< nums[i]<<endl;
			if (index == dp.size() && nums[i]) {
				dp.push_back(nums[i]);
			}
			else {
				dp[index] = min(dp[index], nums[i]);
			}
		}
		return dp.size() - 1;
	}
};

Advanced LIS issues:

354. Russian doll envelope problem

Difficulty 299

Given some envelopes marked with width and height, the width and height appear as integer pairs  (w, h) . When the width and height of another envelope are larger than this envelope, this envelope can be put into another envelope, just like a Russian doll.

Please calculate the maximum number of envelopes that can form a set of "Russian doll" envelopes (that is, you can put one envelope in another envelope).

Note:
Rotating envelopes is not allowed.

Example:

Input: envelopes = [[5,4],[6,4],[6,7],[2,3]]
Output: 3 
 Explanation: The maximum number of envelopes is 3, 组合为: [2,3] => [5,4] => [6,7].

In order to meet the meaning of the question, we need to ensure that the found envelopes meet the conditions of w0<w1<w2<...<wn, h0<h1<h2<...<hn, and when we sort all envelopes on a dimension w , At this latitude w, the monotonic requirement is already met. However, since there are equal conditions at latitude w, it is still necessary to determine whether the latitudes of w are equal. For this reason, under the premise that the values ​​of w are different from each other, less than or equal to ≤ and less than <Is equivalent, then we can completely ignore the w dimension after sorting, and only need to consider the h dimension. At this point, the problems we need to solve are:

Given a sequence, we need to find the longest subsequence so that the elements in this subsequence strictly monotonically increase, which is the LIS problem mentioned above.

In order to ignore the w dimension, we only need to consider the h dimension. We can use the h value as the second key of sorting to sort in descending order. In this way, for each w value, the corresponding envelope is in the sorted array If they appear in the descending order of the h value, then these h values ​​cannot form a strictly increasing sequence with a length exceeding 1, that is, the single-point increasing subsequence generated at the latitude of h will not have the same envelope of w, which satisfies the meaning of the question.

After sorting the two-dimensional array, it is converted to the one-dimensional LIS problem above. The code is as follows:

int cmp1(const void *a, const void *b)
{
	if ((*(vector<int>*)a)[0]  == (*(vector<int>*)b)[0] ) {
		return (*(vector<int>*)a)[1] < (*(vector<int>*)b)[1];   // 从大到小排序
	}
	else
	    return (*(vector<int>*)a)[0] > (*(vector<int>*)b)[0];   // 从小到大排序
}
class Solution {
public:
	int res = 0;

	int maxEnvelopes(vector<vector<int>>& envelopes) {
		vector<int>dp;
		qsort(&envelopes[0], envelopes.size(), sizeof(vector<int>(2)), cmp1);
		// for (auto i : envelopes)
		// 	cout << i[0] << ' ' << i[1] << ' ' << endl;
		dp.push_back(INT32_MIN);
		dp.push_back(envelopes[0][1]);
		for (int i = 1; i < envelopes.size(); ++i) {
			int index = lower_bound(dp.begin(), dp.end(), envelopes[i][1]) - dp.begin();
			if (index == dp.size())
				dp.push_back(envelopes[i][1]);
			else
				dp[index] = min(dp[index], envelopes[i][1]);
		}

		return dp.size() - 1;
	}
};

Before knowing this method, the method used is:

class Node {
public:
	static bool flag;
	int a, b, val;
	Node *left;
	Node *right;
	Node(int x, int y) :a(x), b(y) {
		val = 1;
		left = right = nullptr;
	};
	bool operator <(const Node& N)const {
		if (flag) {
			if (a == N.a)
				return b > N.b;
			else
				return a > N.a;
		}
		else {
			if (b == N.b)
				return a > N.a;
			else
				return b > N.b;
		}
	}
};
int cmp(const void *a, const void *b)
{
	return *(*(Node**)a) < *(*(Node**)b);
}
int cmp1(const void *a, const void *b)
{
	if (*(vector<int>*)a == *(vector<int>*)b)
		return *(vector<int>*)a > *(vector<int>*)b;
	else
		return *((vector<int>*)a + 1) > *((vector<int>*)b + 1);
}
bool Node::flag = 1;
class Solution {
public:
	int res = 0;

	int maxEnvelopes(vector<vector<int>>& envelopes) {
        if(envelopes.size()==0)
            return 0;
		vector<Node*>positive;
		for (auto i : envelopes) {
			Node *mid = new Node(i[0], i[1]);
			positive.push_back(mid);
		}
		qsort(&positive[0], positive.size(), sizeof(Node*), cmp);
		for (auto i : positive)
		{
			cout << i->a << ' ' << i->b << ' ' << i->val << ' ' << (i->left == nullptr) << endl;
		}
		int record = positive.size() - 1;
		for (int i = record - 1; i >= 0; --i) {
			if (positive[i]->a < positive[i + 1]->a)
				record = i + 1;
			if (positive[i]->a < positive[record]->a) {
				int k = 0, yu = positive[record]->a;
				bool judge = 0;	//判断是否存在b小且left==null的节点
				while (record + k < positive.size()) {
					if (positive[record + k]->b > positive[i]->b) {
						positive[i]->left = positive[record + k];
						cout << i << ' ' << record + k << endl;
						break;
					}
					else if(positive[record + k]->left==nullptr){
						judge = 1;	//说明a相同的这层存在b小且left==null的节点
					}
					k++;
					if (record + k < positive.size()) {
						if (positive[record + k]->a > yu) {
							yu = positive[record + k]->a;
							if (judge)
								break;
						}
					}
				}
			}
		}
        Node::flag = 0;
		qsort(&positive[0], positive.size(), sizeof(Node*), cmp);
		for (auto i : positive)
		{
			cout << i->a << ' ' << i->b << ' ' << i->val << ' ' << (i->left == nullptr) << endl;
		}
        record = positive.size() - 1;
        int res = 1;
		for (int i = record - 1; i >= 0; --i) {
			if (positive[i]->b < positive[i + 1]->b)
				record = i + 1;
			if (positive[i]->b < positive[record]->b) {
				int k = 0, yu = positive[record]->b;
				bool judge = 0;	//判断是否存在b小且left==null的节点
				while (record + k < positive.size()) {
					if (positive[record + k]->a > positive[i]->a) {
						positive[i]->right = positive[record + k];
						positive[i]->val = max(positive[i]->val, positive[record + k]->val + 1);
                        res = max(res,positive[i]->val);
						cout << i << ' ' << record + k << ' ' << positive[i]->val << endl;
						break;
					}
					else if (positive[record + k]->right == nullptr) {
						judge = 1;	//说明a相同的这层存在b小且left==null的节点
					}
					k++;
					if (record + k < positive.size()) {
						if (positive[record + k]->b > yu) {
							yu = positive[record + k]->b;
							if (judge)
								break;
						}
					}
				}
			}
		}
		return res;
	}
};

Interview Question 08.13. Pile of boxes

Difficulty 38 Favorites Sharing Switch to English to receive dynamic feedback

Pile of boxes. Give you a pile of n boxes, the width of the box is wi, the depth is di, and the height is hi. Boxes cannot be turned over. When stacking boxes, the width, height and depth of the boxes below must be greater than those of the boxes above. Realize a way to build the highest pile of boxes. The height of the box stack is the sum of the heights of each box.

The input uses an array to [wi, di, hi]represent each box.

Example 1:

Input : box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
 Output : 6

Example 2:

Input : box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]
 Output : 10

prompt:

  1. The number of boxes is not more than 3000.

This problem is a three-dimensional LIS problem. The required result is different from the above. It does not require the longest sequence length. Second, it requires the maximum sum of a certain latitude (height). Therefore, the O(nlogn) complexity method cannot be used. It uses the basic O(n2) method. as follows:

bool cmp(vector<int>a, vector<int>b) {
	if (a[2] == b[2]) {
		if (a[1] == b[1]) {
			return a[0] > b[0];
		}
		else
			return a[1] > b[1];
	}
	else
		return a[2] > b[2];
}
class Solution {
public:
	int pileBox(vector<vector<int>>& box) {
		sort(box.begin(), box.end(), cmp);
		vector<int>dp(box.size() + 1, 0);
		int res = 0;
		for (int i = 0; i < dp.size(); ++i) {
			dp[i] = box[i][2];
			for (int j = 0; j < i; ++j) {
				if (box[j][2] > box[i][2] && box[j][1] > box[i][1] && box[j][0] > box[i][0])
					dp[i] = max(dp[i], dp[j] + box[i][2]);
			}
			res = max(res, dp[i]);
		}
		return res;
	}
};

 

Guess you like

Origin blog.csdn.net/Yanpr919/article/details/114369077