LeetCode 321. 拼接最大数

题目描述

321. 拼接最大数

思路分析

解法一:单调栈 + 归并(推荐)

核心思路

  • 从两个数组分别选出长度为 ik-i 的最大子序列(单调栈)。
  • 将两个子序列按字典序归并得到最大结果。
  • 枚举所有可行的 i,取最大值。


复杂度分析

  • 时间复杂度:O((m+n) * k),其中 m、n 为数组长度。
  • 空间复杂度:O(k),用于构造子序列与合并结果。
class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int m = nums1.length;
        int n = nums2.length;
        int[] best = new int[k];

        int start = Math.max(0, k - n);
        int end = Math.min(k, m);

        for (int i = start; i <= end; i++) {
            int[] a = maxSubsequence(nums1, i);
            int[] b = maxSubsequence(nums2, k - i);
            int[] merged = merge(a, b);

            if (greater(merged, 0, best, 0)) {
                best = merged;
            }
        }

        return best;
    }

    private int[] maxSubsequence(int[] nums, int k) {
        int[] stack = new int[k];
        int top = 0;
        int drop = nums.length - k;

        for (int num : nums) {
            while (top > 0 && drop > 0 && stack[top - 1] < num) {
                top--;
                drop--;
            }
            if (top < k) {
                stack[top++] = num;
            } else {
                drop--;
            }
        }

        return stack;
    }

    private int[] merge(int[] a, int[] b) {
        int[] res = new int[a.length + b.length];
        int i = 0;
        int j = 0;

        for (int r = 0; r < res.length; r++) {
            if (greater(a, i, b, j)) {
                res[r] = a[i++];
            } else {
                res[r] = b[j++];
            }
        }

        return res;
    }

    private boolean greater(int[] a, int i, int[] b, int j) {
        while (i < a.length && j < b.length && a[i] == b[j]) {
            i++;
            j++;
        }
        if (j == b.length) {
            return true;
        }
        if (i < a.length && a[i] > b[j]) {
            return true;
        }
        return false;
    }
}
func maxNumber(nums1 []int, nums2 []int, k int) []int {
    best := make([]int, k)
    m, n := len(nums1), len(nums2)

    start := max(0, k-n)
    end := min(k, m)

    for i := start; i <= end; i++ {
        a := maxSubsequence(nums1, i)
        b := maxSubsequence(nums2, k-i)
        merged := merge(a, b)

        if greater(merged, 0, best, 0) {
            best = merged
        }
    }

    return best
}

func maxSubsequence(nums []int, k int) []int {
    stack := make([]int, 0, k)
    drop := len(nums) - k

    for _, num := range nums {
        for drop > 0 && len(stack) > 0 && stack[len(stack)-1] < num {
            stack = stack[:len(stack)-1]
            drop--
        }

        if len(stack) < k {
            stack = append(stack, num)
        } else {
            drop--
        }
    }

    return stack
}

func merge(a []int, b []int) []int {
    res := make([]int, 0, len(a)+len(b))
    i, j := 0, 0

    for i < len(a) || j < len(b) {
        if greater(a, i, b, j) {
            res = append(res, a[i])
            i++
        } else {
            res = append(res, b[j])
            j++
        }
    }

    return res
}

func greater(a []int, i int, b []int, j int) bool {
    for i < len(a) && j < len(b) && a[i] == b[j] {
        i++
        j++
    }

    if j == len(b) {
        return true
    }
    if i < len(a) && a[i] > b[j] {
        return true
    }
    return false
}

func max(a int, b int) int {
    if a > b {
        return a
    }
    return b
}

func min(a int, b int) int {
    if a < b {
        return a
    }
    return b
}

相似题目

题目 难度 考察点
402. 移掉 K 位数字 中等 单调栈
1673. 找出最具竞争力的子序列 中等 单调栈
316. 去除重复字母 中等 单调栈
1081. 不同字符的最小子序列 中等 单调栈
321. 拼接最大数 困难 贪心、归并
本文作者:
本文链接: https://hgnulb.github.io/blog/2025/17324701
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!