题面
解法:与leetcode321不一样的是,那个是最大值,这个是最小值,且需要处理0首位问题。那道题是Hard题中的Hard,无论是思维量还是代码量都是顶级,这道题难度并不弱于那道。
观察到数据量为500级别,可以考虑N^3的解法。那么显然便是动态规划。定义数组dp[i][j][k]为第一个数组枚举到i,第二个数组枚举到j,总共选了k个的最小答案。注意由于是数组对比大小,需要自定义比较函数。
import java.util.*;
public class Solution {
public int[] minNumber(int[] nums1, int[] nums2, int k) {
int m = nums1.length, n = nums2.length;
String[][][] dp = new String[m + 1][n + 1][k + 1];
for (int i = 0; i <= m; ++i) {
for (int j = 0; j <= n; ++j) {
for (int l = 0; l <= k; ++l) {
dp[i][j][l] = "";
}
}
}
dp[1][0][1] = Integer.toString(nums1[0]);
dp[0][1][1] = Integer.toString(nums2[0]);
for (int i = 2; i <= m; ++i) {
dp[i][0][1] = min(dp[i-1][0][1], Integer.toString(nums1[i-1]));
}
for (int j = 2; j <= n; ++j) {
dp[0][j][1] = min(dp[0][j-1][1], Integer.toString(nums2[j-1]));
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
dp[i][j][1] = min(dp[i-1][j-1][1], min(Integer.toString(nums1[i-1]), Integer.toString(nums2[j-1])));
}
}
for (int l = 2; l <= k; ++l) {
for (int i = 0; i <= m; ++i) {
for (int j = Math.max(l - i, 0); j <= n; ++j) {
dp[i][j][l] = String.join("", Collections.nCopies(l, "9"));
if (i > 0 && !dp[i-1][j][l].isEmpty()) {
dp[i][j][l] = min(dp[i][j][l], dp[i-1][j][l]);
}
if (j > 0 && !dp[i][j-1][l].isEmpty()) {
dp[i][j][l] = min(dp[i][j][l], dp[i][j-1][l]);
}
if (j > 0 && !dp[i][j-1][l-1].isEmpty()) {
dp[i][j][l] = min(dp[i][j][l], dp[i][j-1][l-1] + Integer.toString(nums2[j-1]));
}
if (i > 0 && !dp[i-1][j][l-1].isEmpty()) {
dp[i][j][l] = min(dp[i][j][l], dp[i-1][j][l-1] + Integer.toString(nums1[i-1]));
}
}
}
}
int[] ret = new int[k];
for (int i = 0; i < k; ++i) {
ret[i] = dp[m][n][k].charAt(i) - '0';
}
return ret;
}
private String min(String a, String b) {
if(a.length() == 0) return a;
if(b.length() == 0) return b;
if(a.charAt(0) == '0') a = String.join("", Collections.nCopies(500, "9"));
if(b.charAt(0) == '0') b = String.join("", Collections.nCopies(500, "9"));
return a.compareTo(b) < 0 ? a : b;
}
}