【LeetCode 321】Create Maximum Number

Given two arrays of length m and n with digits 0-9 representing two numbers. 
Create the maximum number of length k <= m + n from digits of the two. 
The relative order of the digits from the same array must be preserved. 
Return an array of the k digits.

Note: You should try to optimize your time and space complexity.

题意:给出两个长度分别为m和n的数组,它们的元素均为数字(0~9),请从中找出K个数字来
组成一个最大的K位数,要求来源于同一个数组中元素在新的数里的相对位置必须和原数组一致。

Example 1:
Input:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
Output:
[9, 8, 6, 5, 3]

Example 2:
Input:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
Output:
[6, 7, 6, 0, 4]

Example 3:
Input:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
Output:
[9, 8, 9]

思路:从数组1中找 i 个数字组成最大的i位数,从数组2中找 K-i 个数字组成最大的K-i位数,然后将它们合并成最大的K位数。i从0到K遍历一遍,从中找出最优的K位数。
问题划分成三个部分:
1)从一个长度为N的数组中抽取最大的包含 i 个元素的数组;
2)将两个长度分别为M和N的数组 合并 成最大的一个数组;
3)i从0到K遍历,找到最优的解。[ i 具体的最小值是 0 和 K-nums2.size() 之间的最大值,i 的最大值同理计算]

1/3 从长度为N的数字数组中抽取最大的 K位数

如 [2,6,0,7,4,4,5,6 ]中最大的3位数是 756, 最大的7位数是 6074456. 为了解决该问题,一个较笨的办法是遍历K次,第一次取出数组中的最大值(保证该最大值后面仍有充足元素可以取的前提下),下一次取该最大值后面部分数组中的最大值... 但有一个时间复杂度更优的方法:单调栈。把数组中的元素依次压入一个单调栈,压入新元素时,若栈顶元素比它小就弹出再比较新的栈顶,直到遇到不比它小的元素,但同时需要注意栈里的元素和剩余数组的元素的个数之和不能比K还小,否则就无法形成K位数了。

vector<int> getMax(vector<int>& nums, int k) {
	vector<int> stk;
	for (int i = 0; i < nums.size(); i++) {
		int numLeft = stk.size() + nums.size() - i;
		while ((!stk.empty())&& stk.back() < nums[i] && numLeft > k) {
			stk.pop_back();
			numLeft--;
		}
		stk.push_back(nums[i]);
	}
	stk.resize(k);//取前K位
	return stk;
}

2/3 将两个数组 合并 成一个数组 [难]

如果是两个有序数组合并,那么只需要用两个下标号分别指向两个数组的开头,然后比较下标处的元素大小,大的元素添加进新数组并且下标号加一即可。注意循环结束后需要处理其中一个数组已经取完而另一个数组还没有取完的情况。

但本部分要合并的两个数组是无序的,这时若下标处的元素相等时,必须考虑它后面的元素大小才能决定取哪一个。比如:
A[6,7]和B[6,0,4]合并,若先取B的6,则下一轮A的6比B的0大,继续取6,依次得到[6,6,7,0,4],
若先取A的6,则下一轮A的7比B的6大,继续取7,依次得到[6,7,6,0,4],这才是正确结果。

所以每一步都需要比较两个下标之后剩余数组之间的大小,可以为此定义一个比较函数:

//比较下标ia之后的a数组和下标ib之后的b数组
bool cmp(vector<int>& a,int ia, vector<int>& b,int ib) {
	while(ia<a.size() && ib<b.size()) {
		if (a[ia] > b[ib]) return 1;
		else if (a[ia] < b[ib]) return 0;
		else
			ia++, ib++;
	}
	return ia<a.size();
}

然后是合并函数:

vector<int> merge(vector<int> nums1, vector<int> nums2) {
	int ind1 = 0, ind2 = 0;
	vector<int> ans;
	while (ind1 < nums1.size() && ind2 < nums2.size()) {
		if (cmp(nums1,ind1,nums2,ind2))
			ans.push_back(nums1[ind1++]);
		else
			ans.push_back(nums2[ind2++]);
	}
	while (ind1 < nums1.size()) ans.push_back(nums1[ind1++]);
	while (ind2 < nums2.size()) ans.push_back(nums2[ind2++]);
	return ans;
}

3/3 主函数 i从0到K循环,找出最优的K位数

vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
	vector<int> ans;
	for (int i = max(0, k - nums2.size()); i <= min(nums1.size(), k); i++) {
		vector<int> curAns = merge(getMax(nums1, i), getMax(nums2, k - i));
		if (cmp(curAns, 0,ans,0)) ans = curAns;
	}
	return ans;
}

猜你喜欢

转载自blog.csdn.net/sinat_38972110/article/details/82935234