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]
思路:
Many of the posts have the same algorithm. In short we can first solve 2 simpler problem
- Create the maximum number of one array
- Create the maximum number of two array using all of their digits.
/*
* 可分为2步
* 1. Create the maximum number of one array((k1=1,k2=k-k1),(k1=2,k2=k-k1)...)
* 2. Create the maximum number of two array using all of their digits.
*/
public class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int[] rst = new int[k];
int l1 = nums1.length, l2 = nums2.length;
for(int k1=Math.max(0, k-l2); k1<=k && k1<=l1; k1++) {
max = new int[Math.min(k1, l1)]; p = 0;
maxNumber(nums1, 0, k1);
int[] max1 = max;
max = new int[Math.min(k-k1, l2)]; p = 0;
maxNumber(nums2, 0, k-k1);
int[] max2 = max;
int[] merge = merge(max1, max2, k);
if(greater(merge, 0, rst, 0)) rst = merge;
}
return rst;
}
// 思路类似于 316. Remove Duplicate Letters
int[] max;
int p;
public void maxNumber(int[] num, int start, int k) {
if(k == 0) return;
if(num.length-start <= k) {
for(; p<max.length && p<num.length; p++)
max[p] = num[start++];
return;
}
int maxPos = start;
for(int i=start; i<num.length-k+1; i++) {
if(num[i] > num[maxPos]) maxPos = i;
}
max[p++] = num[maxPos];
maxNumber(num, maxPos+1, k-1);
}
// 类似merge sort的merge,但是相等的情况比较特殊
private int[] merge(int[] max1, int[] max2, int k) {
int[] merge = new int[k];
for(int i=0, j=0, p=0; p<k; p++) {
if(i == max1.length) merge[p] = max2[j++];
else if(j == max2.length) merge[p] = max1[i++];
else if(max2[j] > max1[i]) merge[p] = max2[j++];
else if(max2[j] < max1[i]) merge[p] = max1[i++];
else merge[p] = greater(max1, i, max2, j) ? max1[i++] : max2[j++];
}
return merge;
}
// 当num1(从i开始)大于num2(从j开始)时返回true
public boolean greater(int[] num1, int i, int[] num2, int j) {
for(; i<num1.length && j<num2.length; i++, j++) {
if(num1[i] > num2[j]) return true;
if(num1[i] < num2[j]) return false;
}
if(num1.length-i > num2.length-j) return true;
return false;
}
}
2刷:
import java.util.Arrays;
public class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int min1 = Math.max(0, k-nums2.length);
int max1 = Math.min(nums1.length, k);
int[] rst = new int[k];
for(int i=min1; i<=max1; i++) {
int j = k - i;
int[] a = getMax(nums1, i);
int[] b = getMax(nums2, j);
int[] c = merge(a, b);
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
System.out.println(Arrays.toString(c));
if(larger(c, 0, rst, 0))
rst = c;
}
return rst;
}
// 判断2个数组的大小
private boolean larger(int[] a, int start1, int[] b, int start2) {
for(int i=0; i<a.length||i<b.length; i++) {
int x = i+start1, y = i+start2;
if(x == a.length) return false;
if(y == b.length) return true;
if(a[x] > b[y]) return true;
if(a[x] < b[y]) return false;
}
return false;
}
// 合并2个数组
private int[] merge(int[] a, int[] b) {
int[] c = new int[a.length+b.length];
int p=0, q=0;
for(int i=0; i<c.length; i++) {
if(p == a.length) c[i]=b[q++];
else if(q == b.length) c[i]=a[p++];
else if(a[p]>b[q]) c[i]=a[p++];
else if(a[p]<b[q]) c[i]=b[q++];
else if(larger(a, p, b, q)) c[i]=a[p++];
else c[i]=b[q++];
}
return c;
}
// 返回的第一位一定是数组的前a.length-(k-1)中的最大值,可用反证法证明
private int[] getMax(int[] a, int k) {
int[] rst = new int[k];
int startIdx = 0;
for(int i=0; i<k; i++) {
startIdx = getMax2(a, startIdx, k-i-1);
rst[i] = a[startIdx-1];
}
return rst;
}
// 从startIdx开始寻找最大的,预留出k位,返回下一个开始的位置,即前面一个就是要用的数的index
private int getMax2(int[] a, int startIdx, int k) {
if(a.length-startIdx == 1+k)
return ++startIdx;
int max = a[startIdx], rst = startIdx;
for(int i=startIdx; i<a.length-k; i++) {
if(a[i] > max) {
max = a[i];
rst = i;
}
}
return ++rst;
}
}
3刷
import java.util.Arrays;
class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int[] max = new int[k];
for(int i=Math.max(0, k-nums2.length); i<=Math.min(nums1.length, k); i++) {
int j = k - i;
int[] a = new int[i], b = new int[j];
getMax(nums1, i, a, 0, 0, i);
getMax(nums2, j, b, 0, 0, j);
int[] merge = mergeArray(a, b, k);
if(Arrays.toString(merge).compareTo(Arrays.toString(max)) > 0)
max = merge;
}
return max;
}
private int[] mergeArray(int[] a, int[] b, int k) {
int[] c = new int[k];
int i = 0, j = 0;
for(int p=0; p<k; p++)
if(i==a.length) c[p]=b[j++];
else if(j==b.length) c[p]=a[i++];
else if(a[i]>b[j]) c[p]=a[i++];
else if(a[i]<b[j]) c[p]=b[j++];
else if(larger(a, b, i, j)) c[p]=a[i++];
else c[p]=b[j++];
return c;
}
private boolean larger(int[] a, int[] b, int i, int j) {
while(true) {
if(i == a.length) return false;
if(j == b.length) return true;
if(a[i] > b[j]) return true;
if(a[i] < b[j]) return false;
i++; j++;
}
}
// 前几个必须出一个数字:就是个递归的过程
private void getMax(int[] a, int n, int[] ret, int s, int have, int need) {
if(need == 0) return;
int maxIdx = s, max = a[s];
for(int i=s+1; i<=a.length-need; i++) {
if(a[i] > max) {
max = a[i];
maxIdx = i;
}
}
ret[have] = max;
getMax(a, n, ret, maxIdx+1, have+1, need-1);
}
}