12/2
初步想法(超时,但可以优化)
将两个数组合并为一个数组,然后将数组的值存入结构体里,保存该值的原位置。
按值的大小进行降序排序,从大到小取值。
下面代码的做法是每次遍历一遍结构体数组,
选取符合条件的点进入最终的答案数组。
这么做的确能解决问题,因为绝对贪心,保证了每次入队点的数值尽可能的大。
但很明显,有很多冗余的操作,
比如某一个元素被使用过后应该出队,当然这是很好优化的。
但还有个问题是有些元素虽然它们的值很大,但它的位置太过靠后了,
导致这个值不能立刻放入答案数组,且每次循环都得将他们检索一遍。
这里给出优化方案:如果检索到这个数特别大,但无法立刻放入,
显然我们总会将这个值放入答案数组后面的某个位置。
所以我们可以设置一个临时的结构体数组来存放这个值,
并对数组剩余可使用的总元素个数进行减少,
如果后面还有元素出现这种情况,就将那个值插入到临时结构体数组里面。
一旦遍历到临时结构体数组首元素的原位置时,就可以将两数组合并,
并继续进行操作。
显然这么做的时间复杂度符合题目要求。
class Solution
{
public:
struct node
{
int val;
int vec;
int pos;
};
static bool cmp(node a, node b)
{
return a.val > b.val;
}
vector<int> maxNumber(vector<int> &nums1, vector<int> &nums2, int k)
{
int n = nums1.size();
int m = nums2.size();
struct node all[m + n];
vector<int> ans;
for (int i = 0; i < n; i++)
{
all[i].vec = 1;
all[i].val = nums1[i];
all[i].pos = i;
}
for (int i = 0; i < m; i++)
{
all[i + n].vec = 2;
all[i + n].val = nums2[i];
all[i + n].pos = i;
}
sort(all, all + m + n, cmp);
int now1 = 0;
int now2 = 0;
int st = 0;
while (st != n + 1)
{
for (int i = 0; i < n + m; i++)
{
if (all[i].vec == 1 && all[i].pos >= now1 && n - all[i].pos + m - now2 >= k - st)
{
ans.push_back(all[i].val);
now1 = all[i].pos + 1;
st++;
break;
}
if (all[i].vec == 2 && all[i].pos >= now2 && m - all[i].pos + n - now1 >= k - st)
{
ans.push_back(all[i].val);
now2 = all[i].pos + 1;
st++;
break;
}
}
}
return ans;
}
};
类似标程解法
学习了标程的单调栈数据结构后,我开始写这段代码。
其中遇到了许许多多的问题,以及很多意外的发现。
单调栈的剩余元素思想和我上面的改进想法有类似的地方,
边界处理需要很细心。
比较函数应该很简单,当我看到标程的比较函数里带了两个下标,我有点疑惑。
不是比较两个长度为k的数组,为啥还要记录这个东西?
后来我发现它是在合并排序里用到了,
是用来比较两个合并数组目前的大小。
当然可以直接贪心的去合并(我就是这么去做的)
但当左右两数组头元素相同时,必须要比较后面几位元素。
class Solution {
public int[] searchMax(int[] nums,int k){
int n=nums.length;
int []stack = new int[k];
int top = -1;
int remain = n - k;
for (int i = 0; i < n; i++) {
int num = nums[i];
while (top >= 0 && stack[top] < num && remain > 0) {
top--;
remain--;
}
if (top < k - 1) {
stack[++top] = num;
} else {
remain--;
}
}
return stack;
}
public boolean compare(int[] nums1,int[] nums2,int n){
for(int i=0;i<n;i++){
if(nums2[i]>nums1[i]){
return true;
}
if(nums2[i]<nums1[i]){
return false;
}
}
return false;
}
public int[] merge(int[] nums1,int[] nums2){
int n1=nums1.length;
int n2=nums2.length;
if(n1==0){
return nums2;
}
if(n2==0){
return nums1;
}
int[] output=new int[n1+n2];
int st1=0;
int st2=0;
int pos=0;
while(pos!=n1+n2){
if(st2==n2){
output[pos++]=nums1[st1++];
}
else if(st1==n1){
output[pos++]=nums2[st2++];
}
else if(nums1[st1]==nums2[st2]){
int t=0;
while(true)
{
if(st1+t==n1){
output[pos++]=nums2[st2++];
}
else if(st2+t==n2){
output[pos++]=nums1[st1++];
}
else if(nums1[st1+t]>nums2[st2+t]){
output[pos++]=nums1[st1++];
}
else if(nums1[st1+t]<nums2[st2+t]){
output[pos++]=nums2[st2++];
}
else{
t++;
continue;
}
break;
}
}
else if(nums1[st1]>nums2[st2]){
output[pos++]=nums1[st1++];
}
else{
output[pos++]=nums2[st2++];
}
}
return output;
}
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int[] ans=new int[k];
int m = nums1.length;
int n = nums2.length;
for(int i=Math.max(0, k - n);i<=Math.min(k, m);i++)
{
int[] s1=searchMax(nums1,i);
int[] s2=searchMax(nums2,k-i);
int[] maxNow=merge(s1,s2);
if(compare(ans,maxNow,k)==true){
System.arraycopy(maxNow, 0, ans, 0, k);
}
}
return ans;
}
}