LeetCode 321. Create Maximum Number

321. Create Maximum Number

Hard

Given two arrays of length m and n with digits 0-9 representing two numbers. Create the maximum number of length k <= m + n from digits of the two. The relative order of the digits from the same array must be preserved. Return an array of the k digits.

Note: You should try to optimize your time and space complexity.

Example 1:

Input:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
Output:
[9, 8, 6, 5, 3]
Example 2:

Input:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
Output:
[6, 7, 6, 0, 4]
Example 3:

Input:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
Output:
[9, 8, 9]

题意

给定两个数组nums1和nums2以及一个正整数k,在nums1和nums2中共取k个数字,使得这k个数字顺序排成的正整数数值最大

思路

遍历k在两个数组中所有可能的切分,对于每一个切分,在nums1, nums2中分别找到可以组成最大正整数的子序列,并按照可以组成最大的正整数的原则将nums1, nums2的两个子序列合并,取所有切分中合并得到的最大序列
难点在于合并方法mergeMax的书写。不同于mergeSort里最小合并,最大合并当nums1[i] == nums2[j]时要比较后缀nums1[i:]与后缀nums2[j:]的大小,取后缀大者对应的第i或第j个元素放入merge后的数组。

代码

class Solution {
    /**
    * pick max integer with length {@code k} from {@code nums}
    * ensure {@code k} <= {@code nums}.length
    * @time complexity: O(n)
    */
    private int[] pickMax(int[] nums, int k) {
        int n = nums.length;
        if (n == k) {
            return nums;
        }
        int[] ret = new int[k];
        int left = 0, right = 0, i = 0, cur = left;
        for (i=0; i<k; ++i) {
            right = n - k + i;
            for (cur = left; cur <= right; ++cur) {
                if (nums[cur] > ret[i]) {
                    ret[i] = nums[cur];
                    left = cur + 1;
                }
            }
        }
        return ret;
    }
    
    /**
    * merge {@code nums1} and {@code nums2} for max integer
    * @time complexity: O(n1 + n2)
    */
    private int[] mergeMax(int[] nums1, int[] nums2) {
        int n1 = nums1.length, n2 = nums2.length, i = 0, j = 0, k = 0;
        if (n1 == 0) {
            return nums2;
        }
        if (n2 == 0) {
            return nums1;
        }
        int[] merged = new int[n1 + n2];
        while (i < n1 && j < n2) {
            if (nums1[i] > nums2[j]) {
                merged[k++] = nums1[i++];
            } else if (nums2[j] > nums1[i]) {
                merged[k++] = nums2[j++];
            } else {
                if (i + 1 == n1 && j + 1 == n2) {
                    merged[k++] = nums1[i++];
                } else if (i + 1 == n1) {
                    merged[k++] = nums2[j++];
                } else if (j + 1 == n2) {
                    merged[k++] = nums1[i++];
                } else {
                    int ii = i, jj = j;
                    while (++ii < n1 && ++jj < n2 && nums1[ii] == nums2[jj]);
                    if (ii == n1 && jj == n2) {
                        merged[k++] = nums1[i++];
                    } else if (ii == n1) {
                        merged[k++] = nums2[j++];
                    } else if (jj == n2) {
                        merged[k++] = nums1[i++];
                    } else if (nums1[ii] > nums2[jj]) {
                        merged[k++] = nums1[i++];
                    } else {
                        merged[k++] = nums2[j++];
                    }
                }
            }
        }
        while (i < n1) {
            merged[k++] = nums1[i++];
        }
        while (j < n2) {
            merged[k++] = nums2[j++];
        }
        return merged;
    }
    
    /**
    * compare two integers represented by two arrays with same length
    * @param nums1
    * @param nums2
    * @return -1: nums1 < nums2; 0: nums1 = nums2; 1: nums1 > nums2
    * @time complexity: O(n)
    */
    private int compareArray(int[] nums1, int[] nums2) {
        int n = nums1.length, i = 0;
        for (i=0; i<n; ++i) {
            if (nums1[i] < nums2[i]) {
                return -1;
            } else if (nums1[i] > nums2[i]) {
                return 1;
            }
        }
        return 0;
    }
    
    /**
    * @time complexity: O(k(n1+n2))
    */
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int n1 = nums1.length, n2 = nums2.length, i = 0;
        int[] ans = new int[k];
        for (i=Math.max(0, k-n2); i<=Math.min(n1, k); ++i) {
            int[] p1 = pickMax(nums1, i);
            int[] p2 = pickMax(nums2, k - i);
            int[] merged = mergeMax(p1, p2);
            // printArray(p1);
            // printArray(p2);
            // printArray(merged);
            // System.out.println();
            if (compareArray(merged, ans) == 1) {
                ans = merged;
            }
        }
        return ans;
    }
    
    /**
    * for debug
    */
    private void printArray(int[] nums) {
        for (int num: nums) {
            System.out.print(num);
        }
        System.out.println();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值