第十二周leetcode算法设计与分析作业

  1. Create Maximum Number

https://leetcode.com/problems/create-maximum-number/description/
Difficulty:Hard
Total Accepted:27.3K
Total Submissions:109.3K
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.

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]

这道题看上去确实比较复杂,一下子让人摸不着头脑。
题目的意思大致为,在不改变一个序列的序列内的字符串相对位置的情况下求出长度为K 的最大拼接字符串。

总的思路如下:

  • 分别找出两个子字符串的最大子序列,在nums1(长度为m)和nums2(长度为n)中挑选出i(max(0, k - n) <= i <= min(m, k) 和k-i个数
  • 将两个子序列拼接在一起。

有了上面的总思路,整个流程也就相对清晰了。主要的就是两个函数的实现,一个是找出最大子序列,一个是在不改变相对位置的情况下拼接。

先说找最大子序列这个函数的实现,基本思路如下:

  • 因为子序列个数必然小于该字符串,假设要从vec1中选出i个数字,首先创造出一个i长度的vector,先将vec1的前i个加进去。接下来,对于后面的每一个想要加进来的数字,首先将vector里面的第一个小于后面的数字踢掉,其余的前进一位,然后把新的加到最后面。如果没有小于后面的数,则将新加进来的数和vector最后一个比较,如果更大的话则替代掉最后一个。
  • 例子如下:
9 5 8 3
加入4
踢掉5,4加到尾部
9 8 3 4
加入2
踢掉3,2加到尾部
9 8 4 2

下面是合并函数的基本思路:

  • 先考虑下面两个情况:
合并:8 9 和3 4 2
合并:6 7 和 6 0 4
  • 对于第一个例子,显然比较好判断,逐个比较两个数的头部,哪个更大先合并哪一个。
  • 对于第二个例子,显然没那么好判断。毕竟两个数字头部都是6。当然根据分析知道要先将6 7放进去,因为第一个6后面跟着7,而第二个6后面只是0。经过分析,解决方法是:如果遇到相同的数字,比较跟在他们后面的序列大小。
  • 例如,上面的第二个例子,跟着的两个序列一个是7,另一个是04,显然7比04要大。具体实现比较两个不同长度的序列大小,方法可以是转为数字或者加0补齐等等。

综上,总的程序实现如下:

class Solution {
public:
	vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
		vector<int> result(k, 0);
		int m = nums1.size(), n = nums2.size();
		for (int i = max(0, k - n); i <= min(m, k); i++) {
			vector<int> sub1 = findMaxSubArr(nums1, i);
			vector<int> sub2 = findMaxSubArr(nums2, k - i);
			vector<int> mergeTemp = mergeSubArr(sub1, sub2);
			if (compareVec(result, 0, mergeTemp, 0))result = mergeTemp;
		}
		return result;
	}
	bool compareVec(vector<int> vec1, int num1, vector<int> vec2, int num2) {//后面更大,返回false
		//先补齐长度
		if (num1 > vec1.size())return false;
		if (num2 > vec2.size())return true;
		int length1 = vec1.size() - num1;
		int length2 = vec2.size() - num2;
		vector<int> res1(max(length1, length2), 0);
		vector<int> res2(max(length1, length2), 0);
		if (length1 >= length2) {//补vec2
			for (int i = 0; i < length1; i++) {
				res1[i] = vec1[i + num1];
			}
			for (int i = 0; i < length2; i++) {
				res2[i + length1 - length2] = vec2[i + num2];
			}
		}
		else {
			for (int i = 0; i < length2; i++) {
				res2[i] = vec2[i + num2];
			}
			for (int i = 0; i < length1; i++) {
				res1[i + length2 - length1] = vec1[i + num1];
			}

		}
		int i = 0;
		while (i < res1.size() && res1[i] == res2[i]) {
			i++;
		}
		return res1[i] < res2[i];
	}
	//分别找出两个子字符串的最大子序列,长度为nums1(长度为m)和nums2(长度为n)中挑选出i(max(0, k - n) <= i <= min(m, k) 和k-i个数
	vector<int> findMaxSubArr(vector<int> vec, int i) {
		vector<int> subArr(i, 0);
		if (i == 0)return subArr;
		//将前i个先写入
		for (int j = 0; j < i; j++) {
			subArr[j] = vec[j];
		}
		//每塞入一个把subArr中第一个小于后面的数给踢出
		for (int j = i; j < vec.size(); j++) {
			int pos = -1;
			for (int x = 0; x < i - 1; x++) {
				if (subArr[x] < subArr[x + 1]) {
					pos = x;
					break;
				}
			}
			//没找到,就和最后一个比较
			if (pos == -1 && subArr[i - 1] < vec[j]) {
				subArr[i - 1] = vec[j];
			}
			else if (pos != -1) {
				for (int x = pos; x < i - 1; x++) {
					subArr[x] = subArr[x + 1];
				}
				subArr[i - 1] = vec[j];
			}
		}
		return subArr;
	}

	//合并两个最大子序列
	vector<int> mergeSubArr(vector<int>& nums1, vector<int>& nums2) {
		int num1Length = nums1.size(), num2Length = nums2.size();
		int i = 0, j = 0;
		vector<int> mergeArr(num1Length + num2Length, 0);
		if (!num1Length)return nums2;
		if (!num2Length)return nums1;
		while (i +j <num1Length+ num2Length) {
			if (j==num2Length|| 
				i < num1Length  && 
				(nums1[i] > nums2[j] || 
				(nums1[i] == nums2[j] && !compareVec(nums1, i + 1, nums2, j + 1)))) {
				mergeArr[i+j] = nums1[i];
				i++;
			}
			else {
				mergeArr[i+j] = nums2[j];
				j++;
			}
		}
		return mergeArr;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值