Leetcode321 A failed dynamic programming attempt

topic:

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.


Wrong solution: dynamic programming

The question can be expressed as choosing k numbers from m+n numbers to maximize the number of combinations. It is easy to think of the 01 knapsack problem. Choose a number from the number sequence with the "knapsack capacity" of k to maximize the number of combinations.
But in fact, this problem does not have an optimal substructure, which is different from the value accumulation of the 01 knapsack problem. In the 01 knapsack problem, the solution that maximizes the value of the first k items must also maximize the value of the first k-1 items. On the standard of maintaining the original order of numbers to form the largest number, the optimal solution of a small-scale problem cannot be used as the basis for the optimal solution of a large-scale problem, so dynamic programming cannot be used for this problem.

The following are the pits I have stepped on, not ac.

nums1Length len1, nums2length len2, len=len1+len2
use a structure to represent the number selection plan:

struct selection{
    
    
        vector<int> n1, n2;
    };
  • The selection state
    selection dp[i][x],0<=i<=len,0<=x<=krepresents numsthe scheme of taking x number from the first i numbers (0~i-1), so that the number of x numbers create()generated according to the rule is the largest.
  • State transition equation
    • If you choose nums[i-1], the temporary scheme temp1
      • 0<=i-1<len1 The
        temporary plan is:
        temp1 = dp[i-1][x-1]
        temp1.n1.emplace_back(nums[i-1])
      • The
        temporary plan for len1<=i<len is:
        temp1 = dp[i-1][x-1]
        temp1.n2.emplace_back(nums[i-1])
    • If nums[i] is not selected, temporary scheme temp2
      temp2 = dp[i-1][x]

dp[i][x] = judge(temp1, temp2) ? temp1 : temp2;

  • Boundary
    guarantee i,x>=1, need to initialize row 0, column 0 is empty scheme
  • The processing sequence
    involves upper left and upper, and the processing sequence is from top to bottom and from left to right.
class Solution {
    
    
public:
    struct selection{
    
    
        vector<int> n1, n2;
    };

    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
    
    
        int len1=nums1.size(), len2=nums2.size(), len=len1+len2;
        vector<int> ans;
        if(len==0) return ans;
        selection dp[len+1][k+1];
        //填表
        for(int i=1; i<=len; i++){
    
    
            for(int x=1; x<=k; x++){
    
    
                //若选nums[i-1]
                selection temp1 = dp[i-1][x-1];
                if(i-1<len1) temp1.n1.emplace_back(nums1[i-1]);
                else temp1.n2.emplace_back(nums2[i-1-len1]);
                //若不选nums[i-1]
                selection temp2 = dp[i-1][x];
                //判断temp1和temp2谁大
                dp[i][x] = judge(temp1, temp2) ? temp1 : temp2;
            }
        }
        create(dp[len][k], ans);
        return ans;
    }

    bool judge(selection &a, selection &b){
    
    
        //判断a是否比b更好
        vector<int> an, bn;
        create(a, an);
        create(b, bn);
        int sa=an.size(), sb=bn.size();
        if(sa>sb) return true;
        else if(sa<sb) return false;
        else{
    
    
            for(int i=0; i<sa; i++){
    
    
                if(an[i]>bn[i]) return true;
                else if(an[i]<bn[i]) return false;
            }
            return false;
        }
    }

    void create(selection &a, vector<int> &an){
    
    
        int t1=a.n1.size(), t2=a.n2.size(), p1=0, p2=0;
        while(p1<t1 && p2<t2){
    
    
            bool out = true;
            int i;
            for(i=0; p1+i<t1 && p2+i<t2; i++){
    
    
                if(a.n1[p1+i]!=a.n2[p2+i]){
    
    
                    if(a.n1[p1+i]>a.n2[p2+i]) an.emplace_back(a.n1[p1++]);
                    else an.emplace_back(a.n2[p2++]);
                    out = false;
                    break;
                }
            }
            if(out){
    
    
                if(p1+i>=t1) an.emplace_back(a.n2[p2++]);
                else an.emplace_back(a.n1[p1++]);
            }
        }
        while(p1<t1) an.emplace_back(a.n1[p1++]);
        while(p2<t2) an.emplace_back(a.n2[p2++]);
        return;
    }
};

Solution: There is a strategy to choose the number

The scheme that constitutes the maximum number must be the maximum number under the same conditions in nums1 and nums2.
Enumerate nums1 and 2 to take several numbers.
ac code:

class Solution {
    
    
public:
    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
    
    
        int len1=nums1.size(), len2=nums2.size();
        vector<int> ans;
        for(int n1=0; n1<=min(len1, k); n1++){
    
    
            int n2 = k - n1;
            if(n2>len2) continue;
            vector<int> se1, se2, res;
            getNumbers(nums1, se1, n1);
            getNumbers(nums2, se2, n2);
            create(se1, se2, res);
            if(judge(res, ans)) ans = res;
        }
        return ans;
    }

    void getNumbers(vector<int>& nums, vector<int>& se, int k){
    
    
        vector<int>::iterator s = nums.begin();
        vector<int>::iterator e = nums.end() - k + 1;
        while(k--){
    
    
            vector<int>::iterator it = max_element(s, e);
            se.emplace_back(*it);
            s = it + 1;
            e++;
        }
        return;
    }

    void create(vector<int>& a, vector<int>& b, vector<int>& res){
    
    
        int t1=a.size(), t2=b.size(), p1=0, p2=0;
        while(p1<t1 && p2<t2){
    
    
            bool out = true;
            int i;
            for(i=0; p1+i<t1 && p2+i<t2; i++){
    
    
                if(a[p1+i]!=b[p2+i]){
    
    
                    if(a[p1+i]>b[p2+i]) res.emplace_back(a[p1++]);
                    else res.emplace_back(b[p2++]);
                    out = false;
                    break;
                }
            }
            if(out){
    
    
                if(p1+i>=t1) res.emplace_back(b[p2++]);
                else res.emplace_back(a[p1++]);
            }
        }
        while(p1<t1) res.emplace_back(a[p1++]);
        while(p2<t2) res.emplace_back(b[p2++]);
        return;
    }

    bool judge(vector<int>& a, vector<int>& b){
    
    
        int sa=a.size(), sb=b.size();
        if(sa>sb) return true;
        else if(sa<sb) return false;
        else{
    
    
            for(int i=0; i<sa; i++){
    
    
                if(a[i]>b[i]) return true;
                else if(a[i]<b[i]) return false;
            }
            return false;
        }
    }
};

Guess you like

Origin blog.csdn.net/sinat_37517996/article/details/104850858