LeetCode321. 拼接最大数

本文深入探讨了如何从两个数字数组中选取k个数字组成最大可能的数值,详细解析了算法设计思路,包括如何保持原数组顺序的同时选择最优数字组合,并提供了具体的实现代码。

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

给定长度分别为 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]

链接:https://leetcode-cn.com/problems/create-maximum-number

看到这道题,原以为很简单,依次选,选大的就好啊,但是当两边一样大的时候,就纠结了,然后用了一个方法,超时。有用了一个方法,内存超了。
最后突然有了灵感,如果选500个数,那就可能0+500,1+499,2+498…
而这时候只要考虑两个小算法就行,第一个就是在数组内找到指定长度的最大值。第二个就是拼接两个值成最大值
答案:

public int[] maxNumber(int[] nums1, int[] nums2, int k) {
    int[] ans = null;
    for (int i = 0; i <= k; i++) {
        if (i == 1) {
            System.out.println();
        }
        if (nums2.length < k - i || i > nums1.length) {
            continue;
        }
        int[] ans1 = getF(nums1, i);
        int[] ans2 = getF(nums2, k - i);
        int[] anss = getFF(ans1, ans2);
        if (ans == null || lager(anss, ans)) {
            ans = anss;
        }
    }
    return ans;
}

//拼接两个数组
private int[] getFF(int[] ans1, int[] ans2) {
    int[] ans = new int[ans1.length + ans2.length];
    int key = 0;
    for (int i = 0, j = 0; i < ans1.length || j < ans2.length; ) {
        if (j == ans2.length) {
            ans[key++] = ans1[i++];
        } else if (i == ans1.length) {
            ans[key++] = ans2[j++];
        } else {
            if (lager(ans1, ans2, i, j)) {
                ans[key++] = ans1[i++];
            } else {
                ans[key++] = ans2[j++];
            }
        }
    }
    return ans;
}

//nums1数组中最大的num位值
private int[] getF(int[] nums1, int num) {
    int[] ans = new int[num];
    if (num == 0) {
        return ans;
    }
    int key = -1;
    for (int i = 0; i < nums1.length; i++) {
        if (key + 1 + nums1.length - i == num) {
            ans[++key] = nums1[i];
            continue;
        }
        if (key == -1 || nums1[i] <= ans[key]) {
            if (key == num - 1) {
                continue;
            }
            ans[++key] = nums1[i];
        } else {
            key--;
            i--;
        }
    }
    return ans;
}

private boolean lager(int[] an1, int[] an2) {
    for (int i = 0; i < an1.length; i++) {
        if (an1[i] > an2[i]) {
            return true;
        } else if (an1[i] < an2[i]) {
            return false;
        }
    }
    return false;
}

private boolean lager(int[] an1, int[] an2, int sta1, int sta2) {
    int i = 0;
    for (; i + sta1 < an1.length && i + sta2 < an2.length; i++) {
        if (an1[i + sta1] > an2[i + sta2]) {
            return true;
        } else if (an1[i + sta1] < an2[i + sta2]) {
            return false;
        }
    }
    if (i + sta2 == an2.length) {
        return true;
    }
    return false;
}

附加:
超时算法:

class Solution {
    

    int[] ans;

    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        ans = new int[k];
        maxNum(nums1, 0, nums2, 0, 0, k, false);
        return ans;
    }

    private void maxNum(int[] nums1, int sta1, int[] nums2, int sta2, int key, int k, boolean canH) {
        if (key == k) {
            return;
        }
        if (canH) {
            ans[key] = 0;
        }
        int temp1 = ans[key] - 1;
        int st1 = -1;
        for (int i = sta1; i < nums1.length && i <= (nums1.length + nums2.length) - (sta2 + (k - key)); i++) {
            if (nums1[i] > temp1) {
                temp1 = nums1[i];
                st1 = i;
            }
        }
        int st2 = -1;
        int temp2 = ans[key] - 1;
        for (int i = sta2; i < nums2.length && i <= (nums1.length + nums2.length) - (sta1 + (k - key)); i++) {
            if (nums2[i] > temp2) {
                temp2 = nums2[i];
                st2 = i;
            }
        }
        if (temp1 > temp2) {
            if (temp1 < ans[key]) {
            } else if (temp1 == ans[key]) {
                maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k, false | canH);
            } else {
                ans[key] = temp1;
                maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k, true);
            }
            return;
        }
        if (temp1 < temp2) {
            if (temp2 < ans[key]) {
            } else if (temp2 == ans[key]) {
                maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k, false | canH);
            } else {
                ans[key] = temp2;
                maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k, true);
            }
            return;
        }
        if (temp1 < ans[key]) {
        } else if (temp1 == ans[key]) {
            maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k, false | canH);
        } else {
            ans[key] = temp1;
            maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k, true);
        }
        canH = false;

        if (temp2 < ans[key]) {
        } else if (temp2 == ans[key]) {
            maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k, false | canH);
        } else {
            ans[key] = temp2;
            maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k, true);
        }
    }
}

超内存算法:

class Solution {
    

    int[] ans;

    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        bbb = new boolean[nums1.length + 1][nums2.length + 1];
        anss = new int[nums1.length + 1][nums2.length + 1][k];
        ans = new int[k];
        ans = maxNum(nums1, 0, nums2, 0, 0, k);
        return ans;
    }

    boolean[][] bbb;
    int[][][] anss;

    private int[] maxNum(int[] nums1, int sta1, int[] nums2, int sta2, int key, int k) {
        if (key == k) {
            return new int[0];
        }
        if (bbb[sta1][sta2]) {
            return anss[sta1][sta2];
        }
        bbb[sta1][sta2] = true;
        int temp1 = -1;
        int st1 = -1;
        for (int i = sta1; i < nums1.length && i <= (nums1.length + nums2.length) - (sta2 + (k - key)); i++) {
            if (nums1[i] > temp1) {
                temp1 = nums1[i];
                st1 = i;
            }
        }
        int st2 = -1;
        int temp2 = -1;
        for (int i = sta2; i < nums2.length && i <= (nums1.length + nums2.length) - (sta1 + (k - key)); i++) {
            if (nums2[i] > temp2) {
                temp2 = nums2[i];
                st2 = i;
            }
        }
        if (temp1 > temp2) {
            int[] an = maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k);
            int[] ann = new int[an.length + 1];
            ann[0] = temp1;
            for (int i = 0; i < an.length; i++) {
                ann[i + 1] = an[i];
            }
            anss[sta1][sta2] = ann;
            return ann;
        }
        if (temp1 < temp2) {
            int[] an = maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k);
            int[] ann = new int[an.length + 1];
            ann[0] = temp2;
            for (int i = 0; i < an.length; i++) {
                ann[i + 1] = an[i];
            }
            anss[sta1][sta2] = ann;
            return ann;
        }
        int[] an1 = maxNum(nums1, st1 + 1, nums2, sta2, key + 1, k);
        int[] an2 = maxNum(nums1, sta1, nums2, st2 + 1, key + 1, k);
        if (lager(an1, an2)) {
            int[] ann = new int[an1.length + 1];
            ann[0] = temp1;
            for (int i = 0; i < an1.length; i++) {
                ann[i + 1] = an1[i];
            }
            anss[sta1][sta2] = ann;
            return ann;
        } else {
            int[] ann = new int[an2.length + 1];
            ann[0] = temp1;
            for (int i = 0; i < an2.length; i++) {
                ann[i + 1] = an2[i];
            }
            anss[sta1][sta2] = ann;
            return ann;
        }
    }

    private boolean lager(int[] an1, int[] an2) {
        for (int i =0; i < an1.length; i++) {
            if (an1[i] > an2[i]) {
                return true;
            } else if (an1[i] < an2[i]) {
                return false;
            }
        }
        return false;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值