Leetcode_321_拼接最大数_贪心_单调栈

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; //[0,n-1]
		int now2 = 0; //[0,m-1]
		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;
        //除掉k个元素外的数组剩余元素
        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 {
    
    
                //stack[top]>=num,该元素直接扔掉
                remain--;
            }
        }
        return stack;
    }
    //判单nums1是不是比nums2小
    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;
    }
}

猜你喜欢

转载自blog.csdn.net/HDUCheater/article/details/110493278