LeetCode -- Create Maximum Number
Question:
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. You should try to optimize your time and space complexity.
Example 1:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
return [9, 8, 6, 5, 3]
Example 2:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
return [6, 7, 6, 0, 4]
Example 3:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
return [9, 8, 9]
Analysis:
给出长度分别为m和n,由数字0-9构成的两个数组。给定一个k <= m + n,创建一个长度为k的最大数字,其中的数字由给出的两个数组决定,且同一个数组中数字的先后顺序要保持。
思路:
解决这个题目主要要解决两个子问题:
1)每个数组中要拿出几个数字?
2)拿出的这几个数字是什么?
3)如何将两个基本有序的数组合并成一个?
这样,分别从两个数组中取出一个子数组后,将两个子数组合并就可以了。
所以我们首先解决第一个问题:
- 每个数组中要拿出几个数字?方法只能是分情况讨论,然后遍历所有的组合可能;
然后,解决第二个问题:
-
拿出的这几个数字是什么?用一个栈保存当前结果。所有对于某个元素只有两种可能:一种是入栈,一种是更新。
-
当 栈不空 && 后面还有足够的数字可以形成长度为k的数组 && 栈顶元素<当前元素,则应该用当前元素替换栈顶元素;
-
其他情况下入栈就可以了。
最后,合并两个子数组。
- 类似两个链表merge的操作,每次选择两者中最大的一个即可。
代码如下:
public class Solution { public int[] maxNumber(int[] nums1, int[] nums2, int k) { if(k == 0) return new int[0]; int m = nums1.length, n = nums2.length; if(m + n < k) return null; if(m + n == k) { int[] res = makeMerge(nums1, nums2, k); return res; } else { //m+n > k int max = m >= k ? k : m; //max means the max number of stack1 int min = n >= k ? 0 : k-n; int[] res = new int[k]; for(int i=0; i<k; i++) res[i] = -0x7ffffffe; for(int i=min; i<=max; i++) { int[] temp = makeMerge(getMax(nums1, i), getMax(nums2, k-i), k); res = isGreater(res, 0, temp, 0) ? res : temp; } return res; } } private int[] makeMerge(int[] nums1, int[] nums2, int k) { int[] res = new int[k]; if(k == 0) return res; int i = 0, j = 0; for(int t=0; t<k; t++ ) { res[t] = isGreater(nums1, i, nums2, j) ? nums1[i++] : nums2[j++]; } return res; } private boolean isGreater(int[] nums1, int i, int[] nums2, int j) { // TODO Auto-generated method stub for(; i<nums1.length && j<nums2.length; i++, j++) { if(nums1[i] > nums2[j]) return true; if(nums1[i] < nums2[j]) return false; } return i != nums1.length; } private int[] getMax(int[] nums, int k) { if(k == 0) return new int[0]; int[] res = new int[k]; int i = 0; for(int j=0; j<nums.length; j++) { while(nums.length - j + i > k && i > 0 && res[i-1] < nums[j]) i--; if(i < k) res[i++] = nums[j]; } return res; } }