文章目录
- 1. 题目
- 2. 解题
1. 题目
给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字。
现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要求从同一个数组中取出的数字保持其在原数组中的相对顺序。
求满足该条件的最大数。结果返回一个表示该最大数的长度为 k 的数组。
说明: 请尽可能地优化你算法的时间和空间复杂度。
示例 1:
输入:
nums1 = [3, 4, 6, 5]
nums2 = [9, 1, 2, 5, 8, 3]
k = 5
输出:
[9, 8, 6, 5, 3]示例 2:
输入:
nums1 = [6, 7]
nums2 = [6, 0, 4]
k = 5
输出:
[6, 7, 6, 0, 4]示例 3:
输入:
nums1 = [3, 9]
nums2 = [8, 9]
k = 3
输出:
[9, 8, 9]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/create-maximum-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题
采用动态规划,long long 存不下,溢出,采用string,超时
class Solution {
public:vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {int m = nums1.size(), n = nums2.size();typedef long long ll;vector<vector<vector<ll>>> dp(k+1, vector<vector<ll>>(m+1, vector<ll>(n+1, -1)));dp[0][0][0] = 0;string str;for(int t = 1; t <= k; t++) {for(int i = 0; i <= m; i++){ for(int j = 0; j <= n; j++){if(dp[t-1][i][j] == -1)continue;if(i < m){dp[t][i+1][j] = max(dp[t][i+1][j], dp[t-1][i][j]*10+nums1[i]);dp[t-1][i+1][j] = max(dp[t-1][i+1][j], dp[t-1][i][j]);} if(j < n){dp[t][i][j+1] = max(dp[t][i][j+1], dp[t-1][i][j]*10+nums2[j]);dp[t-1][i][j+1] = max(dp[t-1][i][j+1], dp[t-1][i][j]);}}}}vector<int> ans(k, 0);ll res = 0;for(int i = 0; i <= m; ++i){for(int j = 0; j <= n; ++j)res = max(res, dp[k][i][j]);}for(int i = k-1; i >= 0; --i){ans[i] = res%10;res /= 10;}return ans;}
};
string 超时
class Solution {
public:vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {int m = nums1.size(), n = nums2.size();vector<vector<vector<string>>> dp(k+1, vector<vector<string>>(m+1, vector<string>(n+1, "#")));dp[0][0][0] = "/";string str;for(int t = 1; t <= k; t++) {for(int i = 0; i <= m; i++){ for(int j = 0; j <= n; j++){if(dp[t-1][i][j] == "#")continue; if(i < m){str = to_string(nums1[i]);dp[t][i+1][j] = max(dp[t][i+1][j], dp[t-1][i][j]+str);dp[t-1][i+1][j] = max(dp[t-1][i+1][j], dp[t-1][i][j]);} if(j < n){str = to_string(nums2[j]);dp[t][i][j+1] = max(dp[t][i][j+1], dp[t-1][i][j]+str);dp[t-1][i][j+1] = max(dp[t-1][i][j+1], dp[t-1][i][j]);}}}}vector<int> ans(k, 0);string res = "";for(int i = 0; i <= m; ++i){for(int j = 0; j <= n; ++j)res = max(res, dp[k][i][j]);}for(int i = 0; i < k; ++i)ans[i] = res[i+1]-'0';return ans;}
};
- 枚举所有可能的长度组合
{i, k-i}
- 从数组里取出 x 个数,使之最大(单调栈法)(参考:LeetCode 5614. 找出最具竞争力的子序列(单调栈))
- 再合并取出来的两个数组(遇到相等的,往后找,找完了,有剩余的先取)
class Solution {vector<int> tmp;
public:vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {int n1 = nums1.size(), n2 = nums2.size();tmp.resize(k);int r = min(n1, k);vector<int> ans;for(int i = 0; i <= r; ++i){if(k-i > n2)continue;auto arr1 = select(nums1, i);auto arr2 = select(nums2, k-i);merge(arr1, arr2, ans);}return ans;}vector<int> select(vector<int>& nums, int k){if(k == nums.size())return nums;vector<int> stk;for(int i = 0; i < nums.size(); ++i){while(!stk.empty() && stk.size()+nums.size()-i > k && stk.back() < nums[i])stk.pop_back();stk.push_back(nums[i]);}stk.resize(k);return stk;}void merge(vector<int>& a1, vector<int>& a2, vector<int>& ans){int n1 = a1.size(), n2 = a2.size(), i = 0, j = 0, idx = 0;while(i < n1 && j < n2){if(compare(a1, i, a2, j) >= 0)tmp[idx++] = a1[i++];elsetmp[idx++] = a2[j++];}while(i < n1)tmp[idx++] = a1[i++];while(j < n2)tmp[idx++] = a2[j++];if(ans.empty())ans = tmp;else if(ans < tmp)ans = tmp;}int compare(vector<int>& a1, int i, vector<int>& a2, int j){int n1 = a1.size(), n2 = a2.size();while(i < n1 && j < n2){int diff = a1[i] - a2[j];if(diff != 0)return diff;i++,j++;}return (n1-i)-(n2-j);//相等话,有剩余的先取}
};
144 ms 20.6 MB C++
我的CSDN博客地址 https://michael.blog.csdn.net/
长按或扫码关注我的公众号(Michael阿明),一起加油、一起学习进步!