单调栈3.拼接最大数

与从一个数组中去除k个数类似,只不过现在是从两个数组中选k个数使其最大,不能改变相对位置,所以需要归并(在未排序的数组中归并)
也就是分别在第一个数组中选k1个数,在第二个数组中选k2个数,然后将他们组合成一个最大的数。分成归和并两步。
选k1个数就利用单调栈来选,选出来是一个单调递减的数组,归并就利用哪个大归并哪个来做。
那怎么确定哪个数组选几个呢,如果第一个数组的长度为m。第二个数组的长度为n,那么k1要大于0小于m,k2要大于0小于n,k1+k2=k,需要遍历所有x和y可能的值。k2等于k-k1,所以遍历k1即可,k1的起点是0和k-n之间的最大值,k1的终点是k和m之间的最小值
对于每一组x和y,都分为分别算两个数组的选出来的数以及合并两个数组这两个过程(类似归并)
1.选出k个数,当成删除len-k个数就行,一定要注意k的值被减完就不能当长度用了,写这个代码写的真脑溢血。
2.合并s1,s2,要注意比较的时候不是比较当前的数大小,如果当前的数一样的话就必须看后面的,所以比较的时候应该是用compare来比较
3.所以compare函数在写的时候要加上下标。

class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int m=nums1.length;
        int n=nums2.length;
        int[] res=new int[k];
        int start=Math.max(0,k-n);
        int end=Math.min(k,m);
        for(int i=start;i<=end;i++){
            int[] s1=subMaxNumber(nums1,i);
            int[] s2=subMaxNumber(nums2,k-i);
            int[] s3=merge(s1,s2);
            if(compare(s3,0,res,0)){
                res=s3;
            }
        }
        return res;
    }
    public int[] subMaxNumber(int[] num, int k) {
       k=num.length-k;
        Deque<Integer> stack=new LinkedList<Integer>();
        for(int i=0;i<num.length;i++){  
            while(k>0 && !stack.isEmpty() && num[i]>stack.peek()){
                stack.pop();
                k--;
            }
            if(num[i]!=0 || !stack.isEmpty()){
                stack.push(num[i]);
            }
        }
        while(k>0 && !stack.isEmpty()){
            stack.pop();
            k--;
        }
        int x=stack.size();
        int[] res=new int[x];
        for(int i=0;i<x;i++){
            res[i]=stack.pollLast();
        }
        return res;
    }

    public int[] merge(int[] nums1, int[] nums2) {
        int[] res = new int[nums1.length + nums2.length];
        int cur = 0, p1 = 0, p2 = 0;
        while (cur < nums1.length + nums2.length) {
            if (compare(nums1, p1, nums2, p2)) { // 不能只比较当前值,如果当前值相等还需要比较后续哪个大
                res[cur++] = nums1[p1++];
            } else {
                res[cur++] = nums2[p2++];
            }
        }
        return res;
    }

    public boolean compare(int[] nums1, int p1, int[] nums2, int p2) {//为什么要传入开始坐标,可以方便merge时的比较
        if (p2 >= nums2.length) return true;
        if (p1 >= nums1.length) return false;
        if (nums1[p1] > nums2[p2]) return true;
        if (nums1[p1] < nums2[p2]) return false;
        return compare(nums1, p1 + 1, nums2, p2 + 1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值