leetcode 321

思路 :单调栈+自定义归并

1.如果单纯地求一个数组nums[n]固定长度k的最大子数组subnums[k]的话,我们使用贪心+单调栈的思想即可解决。

  • 为了保证子数组最大,我们尽可能让大数靠前
  • 首先在保证单调栈的长度最终能够大于等于k,在此基础上保证单调栈的元素尽可能地递减
  • 扫描一遍数组,记当前遍历的元素位置为p,在保证最后单调栈的长度能够达到k的基础上,依次从栈顶弹出小于nums[p]的元素,然后再加入元素nums[p]。
  • 如果栈的元素大于k,需要将多余的元素从栈顶弹出。
    2.如果是两个数组nums1[n1]、nums2[n2]组成的子数组nums[k]的话,假设nums1提供了子数组subnums1[i],nums2提供了子数组subnums2[j],k=i+j;则subnums[i]和subnums[j]必然要是从nums1[n1]和nums2[n2]当中挑选的最大子数组,可以根据1进行计算。
    3.问题就是如何将subnums[i]和subnums[j]拼接成最大数组。
    4.一样采用贪心的思路,尽可能让大数靠前,我们可以参照归并算法,p1遍历subnums1[i],p2遍历subnums2[j]。从subnums1[p1]和subnums2[p2]当中选择较大者将其加入结果数组res当中,那如果两者相等呢?
  • 考虑这种情况,subnums1[3]={6,7,8},subnums2[4]={6,6,5,4},p1=0,p2=0,如果先加入subnums2[p2]的话,最大的数组也就是6678654,而加入p1的话那就是6786654更大
  • 所以我们在两者相等的情况要考虑后面元素的大小,我们选择后面元素更大的对应的那个下标。
  • 再考虑这种情况,subnums1[3]={6,7,8},subnums2[4]={6,7,8,9},也就是其中一个数组是另一个的子数组,我们应该先加入更长的那个数组,这样意味着长数组后面那些大元素可以更早暴露,使得大数尽可能靠前。
    5.我们只需将k枚举拆解成i和j,然后依次构造相应的最大数组,最后从这些最大数组集中取出最大那个即可。

代码

class Solution {
public:
    vector<int> GetSingleStack(vector<int> &nums,int length)
    {
        if(nums.size()==0||length==0)
            return {};
        vector<int> res;
        res.push_back(nums[0]);
        for(int i=1;i<nums.size();i++)
        {
            while(!res.empty()&&nums[i]>res.back()&&res.size()+nums.size()-i>length)
            {
                res.pop_back();
            }
            res.push_back(nums[i]);
        }
        return vector<int>(res.begin(),res.begin()+length);
    }

    vector<int> merge_sort(vector<int>& nums1, vector<int>& nums2)
    {
        vector<int> res;
        int p1=0;
        int p2=0;
        while(p1<nums1.size()&&p2<nums2.size())
        {
            if(cmp(nums1,p1,nums2,p2))
            {
                res.push_back(nums1[p1]);
                p1++;
            }
            else
            {
                res.push_back(nums2[p2]);
                p2++;
            }            
            
        }
        while(p1<nums1.size())
        {
            res.push_back(nums1[p1++]);
        }
        while(p2<nums2.size())
        {
            res.push_back(nums2[p2++]);
        }
        return res;
    }

    bool cmp(vector<int>& nums1,int p1,vector<int>& nums2,int p2)
    {
        while(p1<nums1.size()&&p2<nums2.size())
        {
            if(nums1[p1]==nums2[p2])
            {
                p1++;
                p2++;
            }
            else if(nums1[p1]>nums2[p2])
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        return p1<nums1.size();
    }
    vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
        vector<int> res;
        for(int i=0;i<=k;i++)
        {
            int j=k-i;
            if(i<=nums1.size()&&j<=nums2.size())
            {
                vector<int> t1=GetSingleStack(nums1,i);
                vector<int> t2=GetSingleStack(nums2,j);
                vector<int> t3=merge_sort(t1,t2);
                if(res.empty())
                    res=t3;
                else
                    res=cmp(res,0,t3,0)?res:t3;
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值