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]
这道题给了我们两个数组,里面数字是无序的,又给我们一个k值为k <= m + n,然后我们从两个数组中共挑出k个数,数字之间的相对顺序不变,求能组成的最大的数。
这道题,说实话,我自己肯定想不出来的,这是网上看的做法。
建议和leetcode 402. Remove K Digits 贪心算法 + DFS深度优先遍历 + stack 和 leetcode 738. Monotone Increasing Digits 最大单调递增数字一起学习
代码如下:
import java.util.Arrays;
import java.util.Stack;
/*
* 这个题也需要反思,贪心算法
* 1)分别从nums1(长度为m)和nums2(长度为n)中挑选出i(max(0, k - n) <= i <= min(m, k) 和k-i个数,
* 在保持挑选数组的元素相对顺序不变的情况下,使选出的子数组最大化,主要利用贪心算法进行选取;
* 2)在保持元素相对位置不变的前提下,将数组nums1与nums2合并,使合并的数组最大化。
* */
class Solution
{
public int[] maxNumber(int[] nums1, int[] nums2, int k)
{
int[] result=new int[k];
Arrays.fill(result, 0);
if(nums1==null || nums2==null)
return result;
//根据 k-i<=nums2.length && k-i>=0 推导出来的
for(int i=Math.max(0, k-nums2.length); i<=k && i<=nums1.length;i++)
{
int[] result1 = findKMaxNum(nums1,i);
int[] result2 = findKMaxNum(nums2,k-i);
int a=0,b=0,c=0;
int[] tmp=new int[k];
//归并
while(a<result1.length || b<result2.length)
tmp[c++] = cmp(result1,a,result2,b)? result1[a++] : result2[b++];
if(cmp(tmp,0,result,0))
result=tmp;
}
return result;
}
//比较
private boolean cmp(int[] num1, int i, int[] num2, int j)
{
for(;i<num1.length && j<num2.length;i++,j++)
{
if(num1[i]>num2[j])
return true;
else if(num1[i]<num2[j])
return false;
}
//这个是为了考虑到越界的情况
if(i<num1.length)
return true;
else
return false;
}
/*
* 使用栈得到最大的k个值,同时要保留相关的次序
* 这里是使用数组模拟栈
*/
public int[] findKMaxNum1(int[] nums, int k)
{
int[] reslut=new int[k];
int size=0;
for(int i=0;i<nums.length;i++)
{
while(size>0 && nums.length-i > k-size && reslut[size-1]<nums[i])
size--;
if(size<k)
reslut[size++]=nums[i];
}
return reslut;
}
/*
* 这是使用栈来实现
* */
public int[] findKMaxNum(int[] nums, int k)
{
int[] reslut=new int[k];
Stack<Integer> stack=new Stack<>();
for(int i=0;i<nums.length;i++)
{
while(stack.isEmpty()==false && nums.length-i > k-stack.size() && stack.peek()<nums[i])
stack.pop();
if(stack.size()<k)
stack.push(nums[i]);
}
for(int i=reslut.length-1;i>=0;i--)
reslut[i]=stack.pop();
return reslut;
}
}
下面是C++的做法,就这么做吧,要是遇到这样的题,感觉做不出来
#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <queue>
#include <stack>
#include <string>
#include <climits>
#include <algorithm>
#include <sstream>
#include <functional>
#include <bitset>
#include <numeric>
#include <cmath>
#include <regex>
using namespace std;
class Solution
{
public:
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k)
{
int m = nums1.size(), n = nums2.size();
vector<int> res;
for (int i = max(0, k - n); i <= min(k, m); ++i)
{
res = max(res, mergeVector(maxVector(nums1, i), maxVector(nums2, k - i)));
}
return res;
}
vector<int> maxVector(vector<int> nums, int k)
{
int drop = nums.size() - k;
vector<int> res;
for (int num : nums)
{
while (drop && res.size() && res.back() < num)
{
res.pop_back();
--drop;
}
res.push_back(num);
}
res.resize(k);
return res;
}
vector<int> mergeVector(vector<int> nums1, vector<int> nums2)
{
vector<int> res;
while (nums1.size() + nums2.size())
{
vector<int> &tmp = nums1 > nums2 ? nums1 : nums2;
res.push_back(tmp[0]);
tmp.erase(tmp.begin());
}
return res;
}
};