LeetCode题练习与总结:拼接最大数--321

一、题目描述

给你两个整数数组 nums1nums2,它们的长度分别为 mn。数组 nums1nums2 分别代表两个数各位上的数字。同时你也会得到一个整数 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]

提示:

  • m == nums1.length
  • n == nums2.length
  • 1 <= m, n <= 500
  • 0 <= nums1[i], nums2[i] <= 9
  • 1 <= k <= m + n

二、解题思路

  1. 创建一个辅助函数monoInc,该函数能够从一个数组中找出长度为k的最大单调递增子序列。这个子序列是在保持原数组元素相对顺序的情况下得到的。
  2. 创建另一个辅助函数merge,该函数能够合并两个单调递增的数组,并返回一个长度为k的最大单调递增数组。
  3. maxNumber函数中,遍历所有可能的从nums1中取i个元素,从nums2中取k-i个元素的情况(i的取值范围是0k,并且要满足i <= nums1.lengthk-i <= nums2.length),然后使用merge函数合并这些元素,并保留合并后的最大数组。

三、具体代码

java 复制代码
class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int m = nums1.length, n = nums2.length;
        int[] ans = new int[k];
        for (int i = Math.max(0, k - n); i <= k && i <= m; ++i) {
            int[] candidate = merge(monoInc(nums1, i), monoInc(nums2, k - i), k);
            if (greater(candidate, 0, ans, 0)) {
                ans = candidate;
            }
        }
        return ans;
    }

    private int[] monoInc(int[] nums, int k) {
        int n = nums.length;
        int[] res = new int[k];
        for (int i = 0, j = 0; i < n; ++i) {
            while (n - i > k - j && j > 0 && res[j - 1] < nums[i]) {
                --j;
            }
            if (j < k) {
                res[j++] = nums[i];
            }
        }
        return res;
    }

    private int[] merge(int[] nums1, int[] nums2, int k) {
        int[] res = new int[k];
        for (int i = 0, j = 0, r = 0; r < k; ++r) {
            res[r] = greater(nums1, i, nums2, j) ? nums1[i++] : nums2[j++];
        }
        return res;
    }

    private boolean greater(int[] nums1, int i, int[] nums2, int j) {
        while (i < nums1.length && j < nums2.length && nums1[i] == nums2[j]) {
            ++i; ++j;
        }
        return j == nums2.length || (i < nums1.length && nums1[i] > nums2[j]);
    }
}

在这段代码中:

  • monoInc函数通过贪心算法,维护一个单调递增的序列。
  • merge函数比较两个单调递增序列的元素,并合并成一个新的单调递增序列。
  • greater函数比较两个序列的元素,如果第一个序列在某个位置上的元素更大,或者第二个序列已经结束,则返回true
  • maxNumber函数遍历所有可能的组合,并保留合并后的最大数组。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • maxNumber 函数:

    • 外层循环的次数取决于nums1nums2的长度以及k的值,最坏情况下,循环次数为k
    • 在每次循环中,我们调用monoInc两次和merge一次。
    • greater函数在merge中被调用k次。
  • monoInc 函数:

    • 对于每个数组nums,我们进行一次遍历,时间复杂度为O(n),其中n是数组的长度。
    • 在每次遍历中,可能需要执行一个内部循环来移除不满足条件的元素,最坏情况下,内部循环可能执行k次。
    • 因此,monoInc函数的时间复杂度为O(nk)
  • merge 函数:

    • 这个函数对两个数组合并,每个数组长度为k,因此时间复杂度为O(k)
    • 在合并过程中,我们调用了greater函数,其时间复杂度在最坏情况下为O(k)
  • greater 函数:

    • 这个函数比较两个数组的元素,最坏情况下,它需要遍历整个数组,时间复杂度为O(k)

综合上述分析,总的时间复杂度为: O(k * (O(mk) + O(nk) + O(k) + O(k))) = O(k * (mk + nk + 2k)) = O(k^2 * (m + n + 2)) = O(k^2 * (m + n))

2. 空间复杂度
  • maxNumber 函数:

    • 需要常数空间来存储变量mnansi等。
    • 需要额外空间来存储每次merge函数的返回结果。
  • monoInc 函数:

    • 需要一个长度为k的数组res来存储结果。
  • merge 函数:

    • 需要一个长度为k的数组res来存储合并后的结果。
  • greater 函数:

    • 只需要常数空间。

综合上述分析,总的空间复杂度为:O(k),因为最大的空间占用是在monoIncmerge函数中创建的长度为k的数组。

五、总结知识点

  • 数组的操作

    • 数组的创建、初始化。
    • 数组的索引访问和赋值。
  • 辅助函数(Helper Functions)

    • 使用辅助函数来分解复杂问题,提高代码的可读性和可维护性。
  • 贪心算法

    • monoInc函数实现了贪心算法,通过维护一个单调递增的序列来找到最大子序列。
  • 双指针技术

    • monoInc函数中,使用双指针来维护单调递增序列。
    • merge函数中,使用双指针来合并两个单调递增序列。
  • 递归逻辑

    • greater函数中包含递归逻辑,用于比较两个序列的大小。
  • 循环与迭代

    • 使用for循环和while循环来遍历数组,以及执行迭代操作。
  • 边界条件处理

    • maxNumber函数中,通过Math.max(0, k - n)来确保索引不会超出数组的界限。
  • 逻辑运算

    • 使用逻辑运算符(如&&||!)来控制代码流程。
  • 条件判断

    • 使用ifelse语句进行条件判断。
  • 函数参数传递

    • 通过引用传递(数组)和值传递(基本数据类型)来传递函数参数。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

相关推荐
Algorithm15766 分钟前
JVM是什么,与Java的关系是什么,以及JVM怎么实现的跨平台性
java·开发语言·jvm
DdddJMs__13513 分钟前
C语言 | Leetcode C语言题解之第517题超级洗衣机
c语言·leetcode·题解
遇见你真好。1 小时前
SpringBoot整合quartz定时任务
java·springboot·quartz
Wils0nEdwards1 小时前
Leetcode 合并 K 个升序链表
算法·leetcode·链表
一颗甜苞谷1 小时前
开源一款基于 JAVA 的仓库管理系统,支持三方物流和厂内物流,包含 PDA 和 WEB 端的源码
java·开发语言·开源
Tisfy1 小时前
LeetCode 3211.生成不含相邻零的二进制字符串:二进制枚举+位运算优化
算法·leetcode·二进制·题解·枚举·位运算
攻心的子乐1 小时前
idea使用svn
java·ide·intellij-idea
程序员大佬超1 小时前
IDEA解决 properties 文件乱码问题
java·ide·intellij-idea
秋恬意1 小时前
LinkedList 源码分析
java·开发语言·面试
隔窗听雨眠1 小时前
深入理解Redis的四种模式
java·redis·mybatis