zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    眼过千遍不如手过一遍!
    等老了,做一个视频编辑
    不建议用wxWidgets,底层有过多的bug
    MFC新婚之夜(笑昏,大概是指MFC的人固步自封)
    Twitter算法
    Ruby on rails3
    重提基数排序
    Hashtable Dictionary List
    try { var mergeFilePath = string.Format("{0}mergepdf.pdf", tempDownDir); PDFPrintHelper.MergePDFFile(pdfList, mergeFi
    查找树
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/14638657.html
Copyright © 2011-2022 走看看