321. Create Maximum Number

问题:

给定两个int数组,代表两个数位数值的列表。

从两个数组中,按照已有的顺序选取数位数值,

组成一个新的数,长度为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]
 

Constraints:
m == nums1.length
n == nums2.length
1 <= m, n <= 500
0 <= nums1[i], nums2[i] <= 9
1 <= k <= m + n

  

解法:Greedy + DP

分解问题为子问题:

  • 两个数组中分别选一定数量,总共k个数后,这些数排列成最大的: merge
    • 从nums1中选取 i 个数,maxArry
    • 从nums2中选取 剩下的 k-i 个数。maxArry
    • 能构成最大的数 res。
  • 这个一定量(在两个数组中的分配) i 又可以是 0~k(不超过nums1.size,也不能使得超过nums2.size)

那么所求即为:

所有分配可能中,最大的结果。MAX<i=0~k>{merge(nums1[select i], nums2[select k-i])}

 

子问题 1: maxArry

在nums1中选取 k 个元素,使得到最大值

方法:堆栈弹出法

由于要求保持数列顺序,那我们尽可能将更大的值放在最前面。后面的值都小于前面的值,才能达到要求。

⚠️ 注意:但有可能后面的值都大于前面的值,那我们可不选的数量 pop_num=nums1.size-k 有限,pop完了这些限量后,不能再不选了,余留下来的,也只能保留,但也已经是最大了。

因此,我们从头遍历nums1.

若当前遍历到的数nums1[i]>入选的最后一个值 res.back

那么pop,res的最后一个值,再比较下一个res的最后值。

一直到nums[i]< res.back

则入栈res。

最后所得res,可能超过k,那我们只选择最前面的k个元素即可。res.resize(k);

 1     //from array nums, choose k elements to make a maximum array
 2     //which should keep the relative order.
 3     vector<int> maxArry(vector<int>& nums, int k) {
 4         int pop_nums = nums.size()-k;
 5         if(pop_nums<=0) return nums;
 6         vector<int> res;
 7         for(int i=0; i<nums.size(); i++) {
 8             while(!res.empty() && res.back()<nums[i] && pop_nums>0) {
 9                 res.pop_back();
10                 pop_nums--;
11             }
12             res.push_back(nums[i]);
13         }
14         res.resize(k);
15         return res;
16     }

 

子问题2: merge

合并nums1和nums2,使得获得最大序列。

方法:

遍历nums1和nums2的每一个元素。

每次选取 字典序 最大的一方的第一个元素 入res。

⚠️ 注意:6,7 VS 6,0,4

比较大的是 6,7

字典序的比较方法为,顶头开始比较,后面长度不足的,补零。

即上述,实际比较的是:670 VS 604

如果不用字典序比较,

若出现相同字符,无法判断入res的,选择哪一方。

但实际,我们需要选择,后面更大的一方,方便提前选择这一方的数字,成为更高数位,而使得总数值更大。

 1     //merge 2 arrays to be a maximum array.
 2     //which should keep the relative order.
 3     vector<int> merge(const vector<int>& nums1, const vector<int>& nums2) {
 4         auto s1 = nums1.cbegin();
 5         auto e1 = nums1.cend();
 6         auto s2 = nums2.cbegin();
 7         auto e2 = nums2.cend();
 8         vector<int> res;
 9            // printvec1(res);
10         while(s1!=e1 || s2!=e2) {
11             res.push_back(
12                 lexicographical_compare(s1,e1,s2,e2)? *s2++:*s1++
13             );
14         }
15         return res;
16     }

 

最后 遍历所有两个数列中分配选择数量的可能,选择最大。

代码参考:

 1 class Solution {
 2 public:
 3    /* void printvec(vector<int>::const_iterator v, vector<int>::const_iterator& ve) {
 4         cout<<"{";
 5         while(v!=ve){
 6             cout<< *v++ <<",";
 7         }
 8         cout<<"}"<<endl;
 9     }
10     void printvec1(vector<int> v) {
11         cout<<"{";
12         for(int ve:v){
13             cout<< ve <<",";
14         }
15         cout<<"}"<<endl;
16     }*/
17     vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
18         int n=nums1.size(), m=nums2.size();
19         vector<vector<int>> dp(n+1, vector<int>(m+1,0));
20         vector<int> res;
21         for(int i=0; i<=k; i++) {
22             if(i>n || k-i>m) continue;
23             res = max(res, merge(maxArry(nums1,i), maxArry(nums2, k-i)));
24         }
25         return res;
26     }
27     //merge 2 arrays to be a maximum array.
28     //which should keep the relative order.
29     vector<int> merge(const vector<int>& nums1, const vector<int>& nums2) {
30         auto s1 = nums1.cbegin();
31         auto e1 = nums1.cend();
32         auto s2 = nums2.cbegin();
33         auto e2 = nums2.cend();
34         vector<int> res;
35            // printvec1(res);
36         while(s1!=e1 || s2!=e2) {
37             res.push_back(
38                 lexicographical_compare(s1,e1,s2,e2)? *s2++:*s1++
39             );
40         }
41         return res;
42     }
43     //from array nums, choose k elements to make a maximum array
44     //which should keep the relative order.
45     vector<int> maxArry(vector<int>& nums, int k) {
46         int pop_nums = nums.size()-k;
47         if(pop_nums<=0) return nums;
48         vector<int> res;
49         for(int i=0; i<nums.size(); i++) {
50             while(!res.empty() && res.back()<nums[i] && pop_nums>0) {
51                 res.pop_back();
52                 pop_nums--;
53             }
54             res.push_back(nums[i]);
55         }
56         res.resize(k);
57         return res;
58     }
59 };

 ⚠️ 注意:

这里c++中,max函数,可以比较 vector

 

posted @ 2021-04-09 20:17  habibah_chang  阅读(41)  评论(0编辑  收藏  举报