You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class45;
// 测试链接: https://leetcode.com/problems/create-maximum-number/
public class Code02_CreateMaximumNumber {
public static int[] maxNumber1(int[] nums1, int[] nums2, int k) {
int len1 = nums1.length;
int len2 = nums2.length;
if (k < 0 || k > len1 + len2) {
return null;
}
int[] res = new int[k];
int[][] dp1 = getdp(nums1); // 生成dp1这个表以后从nums1中只要固定拿N个数
int[][] dp2 = getdp(nums2);
// get1 从arr1里拿的数量
// K - get1 从arr2里拿的数量
for (int get1 = Math.max(0, k - len2); get1 <= Math.min(k, len1); get1++) {
// arr1 挑 get1个怎么得到一个最优结果
int[] pick1 = maxPick(nums1, dp1, get1);
int[] pick2 = maxPick(nums2, dp2, k - get1);
int[] merge = merge(pick1, pick2);
res = preMoreThanLast(res, 0, merge, 0) ? res : merge;
}
return res;
}
public static int[] merge(int[] nums1, int[] nums2) {
int k = nums1.length + nums2.length;
int[] ans = new int[k];
for (int i = 0, j = 0, r = 0; r < k; ++r) {
ans[r] = preMoreThanLast(nums1, i, nums2, j) ? nums1[i++] : nums2[j++];
}
return ans;
}
public static boolean preMoreThanLast(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]);
}
public static int[] maxNumber2(int[] nums1, int[] nums2, int k) {
int len1 = nums1.length;
int len2 = nums2.length;
if (k < 0 || k > len1 + len2) {
return null;
}
int[] res = new int[k];
int[][] dp1 = getdp(nums1);
int[][] dp2 = getdp(nums2);
for (int get1 = Math.max(0, k - len2); get1 <= Math.min(k, len1); get1++) {
int[] pick1 = maxPick(nums1, dp1, get1);
int[] pick2 = maxPick(nums2, dp2, k - get1);
int[] merge = mergeBySuffixArray(pick1, pick2);
res = moreThan(res, merge) ? res : merge;
}
return res;
}
public static boolean moreThan(int[] pre, int[] last) {
int i = 0;
int j = 0;
while (i < pre.length && j < last.length && pre[i] == last[j]) {
i++;
j++;
}
return j == last.length || (i < pre.length && pre[i] > last[j]);
}
public static int[] mergeBySuffixArray(int[] nums1, int[] nums2) {
int size1 = nums1.length;
int size2 = nums2.length;
int[] nums = new int[size1 + 1 + size2];
for (int i = 0; i < size1; i++) {
nums[i] = nums1[i] + 2;
}
nums[size1] = 1;
for (int j = 0; j < size2; j++) {
nums[j + size1 + 1] = nums2[j] + 2;
}
DC3 dc3 = new DC3(nums, 11);
int[] rank = dc3.rank;
int[] ans = new int[size1 + size2];
int i = 0;
int j = 0;
int r = 0;
while (i < size1 && j < size2) {
ans[r++] = rank[i] > rank[j + size1 + 1] ? nums1[i++] : nums2[j++];
}
while (i < size1) {
ans[r++] = nums1[i++];
}
while (j < size2) {
ans[r++] = nums2[j++];
}
return ans;
}
public static class DC3 {
public int[] sa;
public int[] rank;
public DC3(int[] nums, int max) {
sa = sa(nums, max);
rank = rank();
}
private int[] sa(int[] nums, int max) {
int n = nums.length;
int[] arr = new int[n + 3];
for (int i = 0; i < n; i++) {
arr[i] = nums[i];
}
return skew(arr, n, max);
}
private int[] skew(int[] nums, int n, int K) {
int n0 = (n + 2) / 3, n1 = (n + 1) / 3, n2 = n / 3, n02 = n0 + n2;
int[] s12 = new int[n02 + 3], sa12 = new int[n02 + 3];
for (int i = 0, j = 0; i < n + (n0 - n1); ++i) {
if (0 != i % 3) {
s12[j++] = i;
}
}
radixPass(nums, s12, sa12, 2, n02, K);
radixPass(nums, sa12, s12, 1, n02, K);
radixPass(nums, s12, sa12, 0, n02, K);
int name = 0, c0 = -1, c1 = -1, c2 = -1;
for (int i = 0; i < n02; ++i) {
if (c0 != nums[sa12[i]] || c1 != nums[sa12[i] + 1] || c2 != nums[sa12[i] + 2]) {
name++;
c0 = nums[sa12[i]];
c1 = nums[sa12[i] + 1];
c2 = nums[sa12[i] + 2];
}
if (1 == sa12[i] % 3) {
s12[sa12[i] / 3] = name;
} else {
s12[sa12[i] / 3 + n0] = name;
}
}
if (name < n02) {
sa12 = skew(s12, n02, name);
for (int i = 0; i < n02; i++) {
s12[sa12[i]] = i + 1;
}
} else {
for (int i = 0; i < n02; i++) {
sa12[s12[i] - 1] = i;
}
}
int[] s0 = new int[n0], sa0 = new int[n0];
for (int i = 0, j = 0; i < n02; i++) {
if (sa12[i] < n0) {
s0[j++] = 3 * sa12[i];
}
}
radixPass(nums, s0, sa0, 0, n0, K);
int[] sa = new int[n];
for (int p = 0, t = n0 - n1, k = 0; k < n; k++) {
int i = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2;
int j = sa0[p];
if (sa12[t] < n0 ? leq(nums[i], s12[sa12[t] + n0], nums[j], s12[j / 3])
: leq(nums[i], nums[i + 1], s12[sa12[t] - n0 + 1], nums[j], nums[j + 1], s12[j / 3 + n0])) {
sa[k] = i;
t++;
if (t == n02) {
for (k++; p < n0; p++, k++) {
sa[k] = sa0[p];
}
}
} else {
sa[k] = j;
p++;
if (p == n0) {
for (k++; t < n02; t++, k++) {
sa[k] = sa12[t] < n0 ? sa12[t] * 3 + 1 : (sa12[t] - n0) * 3 + 2;
}
}
}
}
return sa;
}
private void radixPass(int[] nums, int[] input, int[] output, int offset, int n, int k) {
int[] cnt = new int[k + 1];
for (int i = 0; i < n; ++i) {
cnt[nums[input[i] + offset]]++;
}
for (int i = 0, sum = 0; i < cnt.length; ++i) {
int t = cnt[i];
cnt[i] = sum;
sum += t;
}
for (int i = 0; i < n; ++i) {
output[cnt[nums[input[i] + offset]]++] = input[i];
}
}
private boolean leq(int a1, int a2, int b1, int b2) {
return a1 < b1 || (a1 == b1 && a2 <= b2);
}
private boolean leq(int a1, int a2, int a3, int b1, int b2, int b3) {
return a1 < b1 || (a1 == b1 && leq(a2, a3, b2, b3));
}
private int[] rank() {
int n = sa.length;
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[sa[i]] = i;
}
return ans;
}
}
public static int[][] getdp(int[] arr) {
int size = arr.length; // 0~N-1
int pick = arr.length + 1; // 1 ~ N
int[][] dp = new int[size][pick];
// get 不从0开始因为拿0个无意义
for (int get = 1; get < pick; get++) { // 1 ~ N
int maxIndex = size - get;
// i~N-1
for (int i = size - get; i >= 0; i--) {
if (arr[i] >= arr[maxIndex]) {
maxIndex = i;
}
dp[i][get] = maxIndex;
}
}
return dp;
}
public static int[] maxPick(int[] arr, int[][] dp, int pick) {
int[] res = new int[pick];
for (int resIndex = 0, dpRow = 0; pick > 0; pick--, resIndex++) {
res[resIndex] = arr[dp[dpRow][pick]];
dpRow = dp[dpRow][pick] + 1;
}
return res;
}
}