列表

详情


321. 拼接最大数

给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。

求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。

说明: 请尽可能地优化你算法的时间和空间复杂度。

示例 1:

输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]

示例 2:

输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]

示例 3:

输入:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
输出:
[9, 8, 9]

相似题目

移掉 K 位数字

最大交换

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) { } };

golang 解法, 执行用时: 12 ms, 内存消耗: 6.7 MB, 提交时间: 2023-07-23 11:02:23

func maxSubsequence(a []int, k int) (s []int) {
    for i, v := range a {
        for len(s) > 0 && len(s)+len(a)-1-i >= k && v > s[len(s)-1] {
            s = s[:len(s)-1]
        }
        if len(s) < k {
            s = append(s, v)
        }
    }
    return
}

func lexicographicalLess(a, b []int) bool {
    for i := 0; i < len(a) && i < len(b); i++ {
        if a[i] != b[i] {
            return a[i] < b[i]
        }
    }
    return len(a) < len(b)
}

func merge(a, b []int) []int {
    merged := make([]int, len(a)+len(b))
    for i := range merged {
        if lexicographicalLess(a, b) {
            merged[i], b = b[0], b[1:]
        } else {
            merged[i], a = a[0], a[1:]
        }
    }
    return merged
}

func maxNumber(nums1, nums2 []int, k int) (res []int) {
    start := 0
    if k > len(nums2) {
        start = k - len(nums2)
    }
    for i := start; i <= k && i <= len(nums1); i++ {
        s1 := maxSubsequence(nums1, i)
        s2 := maxSubsequence(nums2, k-i)
        merged := merge(s1, s2)
        if lexicographicalLess(res, merged) {
            res = merged
        }
    }
    return
}

javascript 解法, 执行用时: 84 ms, 内存消耗: 47.1 MB, 提交时间: 2023-07-23 11:00:50

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @param {number} k
 * @return {number[]}
 */
var maxNumber = function(nums1, nums2, k) {
    var r = Array(k).fill(0), end = Math.min(k, nums1.length)
    for(var i = Math.max(0, k - nums2.length); i <= end; i++) 
            r = max(r, merge(maxSubsequence(nums1, i), maxSubsequence(nums2, k - i)))
    return r
};
var maxSubsequence = (nums, k) => {
    var mStack = [], len = nums.length, top = -1, last = len - k
    for(var i = 0; i < len; i++) {
        while (top > -1 && nums[i] > mStack[top] && last > 0) top--, last--
        top < k - 1 ? mStack[++top] = nums[i] : last--
    }
    return mStack
}
var merge = (nums1, nums2) => {
    var p1 = p2 = 0, r = [], len1 = nums1.length, len2 = nums2.length
    while (p1 < len1 || p2 < len2) {
        if (p2 >= len2 || nums1[p1] > nums2[p2]) r.push(nums1[p1++])
        else if (nums1[p1] === nums2[p2]) {
            var _p1 = p1, _p2 = p2
            while(_p1 < len1 && nums1[++_p1] === nums2[++_p2]) {}
            r.push(_p2 >= len2 || nums1[_p1] > nums2[_p2] ? nums1[p1++] : nums2[p2++])
        } else r.push(nums2[p2++])
    }
    return r 
}
var max = (nums1, nums2, p1 = p2 = -1, len1 = nums1.length) => {
    while(p1 < len1 && nums1[++p1] === nums2[++p2]) {}
    return nums2[p2] > nums1[p1] ? nums2 : nums1
}

cpp 解法, 执行用时: 40 ms, 内存消耗: 31.9 MB, 提交时间: 2023-07-23 10:59:26

class Solution {
public:
    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
        vector<int> res(k, 0);
        int n = nums1.size(), m = nums2.size();
        // 假设有最大子序列中有s个元素来自nums1,对所有可能的s值遍历
        for (int s=max(0, k-m); s<=min(k, n); s++){
            vector<int> temp;
            int i = 0, j = 0;
            // nums1中长度为s的最大子序列
            vector<int> temp1 = maxKsequence(nums1, s);
            // nums2中长度为k-s的最大子序列
            vector<int> temp2 = maxKsequence(nums2, k-s);
            // 对两个子序列进行归并
            // lexicographical_compare:比较两个序列的字典序大小
            auto iter1 = temp1.begin(), iter2 = temp2.begin();
            while (iter1 != temp1.end() || iter2 != temp2.end()){
                temp.push_back(lexicographical_compare(iter1, temp1.end(), iter2, temp2.end()) ? *iter2++ : *iter1++);
            }
            // 如果归并后的最大子序列大于目前已找到的最大子序列,则更新解
            res = lexicographical_compare(res.begin(), res.end(), temp.begin(), temp.end()) ? temp : res;
        }
        return res;
    }

    // 求数组v的长度为k的最大子序列
    vector<int> maxKsequence(vector<int> v, int k){
        int n = v.size();
        if (n <= k)
            return v;
        vector<int> res;
        int pop = n-k;
        for (int i=0; i<n; i++){
            while(!res.empty() && v[i]>res.back() && pop-->0)
                res.pop_back();
            res.push_back(v[i]);
        }
        res.resize(k);
        return res;
    }
};

python3 解法, 执行用时: 180 ms, 内存消耗: 16.3 MB, 提交时间: 2023-07-23 10:57:23

class Solution:
    def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
        def pick_max(nums: List[int], k: int):
            stack = []
            drop = len(nums) - k
            for num in nums:
                while drop and stack and stack[-1] < num:
                    stack.pop()
                    drop -= 1
                stack.append(num)
            return stack[:k]

        def merge(A: int, B: int):
            ans = []
            while A or B:
                bigger = A if A > B else B
                ans.append(bigger[0])
                bigger.pop(0)
            return ans

        return max(merge(pick_max(nums1, i), pick_max(nums2, k-i)) for i in range(k+1) if i <= len(nums1) and k-i <= len(nums2))

上一题