Copy class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int len1 = nums1.length, len2 = nums2.length;
if (len1 > len2) return maxNumber(nums2, nums1, k);
if (len1 + len2 == k) return merge(nums1, nums2);
int[] max = new int[k];
for (int i = 0; i <= k && i <= len1; i++) {
int[] selected1 = selectNums(nums1, i);
int[] selected2 = selectNums(nums2, k - i);
int[] mergedArray = merge(selected1, selected2);
if (isGreater(mergedArray, 0, max, 0)) {
max = mergedArray;
}
}
return max;
}
private boolean isGreater(int[] nums1, int start1, int[] nums2, int start2) {
int len1 = nums1.length, len2 = nums2.length;
int i1 = start1, i2 = start2;
while (i1 < len1 && i2 < len2) {
if (nums1[i1] > nums2[i2]) return true;
if (nums1[i1] < nums2[i2]) return false;
i1++;
i2++;
}
// Lexicographical smaller: [1,2,3,4] is greater than [1,2,3]
return i1 < len1;
}
private int[] merge(int[] nums1, int[] nums2) {
int len1 = nums1.length, len2 = nums2.length;
int[] res = new int[len1 + len2];
int index = 0;
int i1 = 0, i2 = 0;
while (i1 < len1 && i2 < len2) {
if (isGreater(nums1, i1, nums2, i2)) {
res[index] = nums1[i1];
i1++;
} else {
res[index] = nums2[i2];
i2++;
}
index++;
}
while (i1 < len1) res[index++] = nums1[i1++];
while (i2 < len2) res[index++] = nums2[i2++];
return res;
}
private int[] selectNums(int[] nums, int n) {
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < nums.length; i++) {
while (!stack.isEmpty() && stack.peek() < nums[i] && isRemainingSufficient(nums, n, i, stack)) {
stack.pop();
}
if (stack.size() < n) stack.push(nums[i]);
}
return stackToArray(stack);
}
private boolean isRemainingSufficient(int[] nums, int n, int i, Deque<Integer> stack) {
return nums.length - i > n - stack.size();
}
private int[] stackToArray(Deque<Integer> stack) {
int[] res = new int[stack.size()];
int i = res.length - 1;
while (!stack.isEmpty()) {
res[i--] = stack.pop();
}
return res;
}
}
// O(k(MN)) time, O(N) space;
//