[Leetcode] 321. Create Maximum Number 解题报告

本文介绍了一种算法,用于从两个整数数组中选取k个数字组成最大可能的数值,同时保持每个数组内数字的相对顺序不变。通过三个步骤实现:选择数组中的最大子序列、合并这些子序列以及枚举所有可能的组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum number of length k <= m + nfrom digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the k digits. You should try to optimize your time and space complexity.

Example 1:

nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
return [9, 8, 6, 5, 3]

Example 2:

nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
return [6, 7, 6, 0, 4]

Example 3:

nums1 = [3, 9]
nums2 = [8, 9]
k = 3
return [9, 8, 9]

思路

我们分三步实现这一算法:1)计算出从nums1中取i个数字,以及从nums2中取k-i个字符分别所能构成的最大数;2)计算从nums1和nums2中所取的这k个数字所能构成的最大数;3)枚举i可能的取值,从中选取可以构成的最大数并返回。

首先我们需要从理论上证明:假设最终构成的最大数是从nums1中取了i个数,那么这i个数必然在nums1中可以形成最大的数(可以利用反证法证明,这里证明从略)。下面我们分别解释每一步的实现:

1)从nums1中选取i个数字,使得这i个数字构成的数最大。这实际上和Leetcode 316这道题目的思路一模一样,具体请见《[Leetcode] 316. Remove Duplicate Letters 解题报告》。可以采用贪心策略,一旦发现还可以删除数字,并且当前要加入的数字比结果集中最后一个数字要大,就把最后一个数字出栈。

2)基于nums1中的选出的这i个数字和nums2中选取出的这k-i个数字,构造最大数。这实际上就是merge sort的变种。每次选取nums1和nums2的头部的最大数并加入结果集。需要注意的是,如果两个头部的数字相等,那么还需要看第二位,如果第二位相同,则还需要看第三位……幸运的是vector<int>的默认比较函数实现的正是这一功能。

3)枚举所有i的可能值,计算可以构成的最大数。

总之,感到这道题目还是挺难的,考查的知识点除了贪心策略,还有归并排序等,我觉得要在面试现场写出bug free的代码还挺不容易的。

代码

class Solution {
public:
    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
        vector<int> result;
        int len1 = nums1.size(), len2 = nums2.size();
        for(int i = max(k - len2, 0); i <= min(k, len1); ++i) {
            // get i digits from nums1, and get (k-i) digits from nums2
            result = max(result, merge(getMax(nums1, i), getMax(nums2, k-i)));
        }
        return result;
    }
private:
    vector<int> getMax(vector<int> &nums, int k) {  // We use greedy algorithm to get the Max vector<int>
        vector<int> vec;                           
        int size = nums.size();
        int drop = size - k;
        for(int i = 0; i < nums.size(); ++i) {
            while(drop > 0 && vec.size() > 0 && nums[i] > vec.back()) {
                --drop;
                vec.pop_back();                     // drop the last element from the vec
            }
            vec.push_back(nums[i]);
        }
        vec.resize(k);
        return vec;
    }
    vector<int> merge(vector<int> nums1, vector<int> nums2) {
        vector<int> vec;  
        while(nums1.size() + nums2.size() > 0) {
            // We compare nums1 and nums2, because we do not only care about the current position, but also the next position
            vector<int>& tem = nums1 > nums2 ? nums1 : nums2;   // vector<int> has the exact compare function that we need
            vec.push_back(tem[0]);  
            tem.erase(tem.begin());  
        }  
        return vec;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值