321. Create Maximum Number

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]



思路:

Many of the posts have the same algorithm. In short we can first solve 2 simpler problem

  1. Create the maximum number of one array
  2. Create the maximum number of two array using all of their digits.

/*
 * 可分为2步
 * 1. Create the maximum number of one array((k1=1,k2=k-k1),(k1=2,k2=k-k1)...)
 * 2. Create the maximum number of two array using all of their digits.
 */
public class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
    	int[] rst = new int[k];
    	int l1 = nums1.length, l2 = nums2.length;
    	
        for(int k1=Math.max(0, k-l2); k1<=k && k1<=l1; k1++) {
        	max = new int[Math.min(k1, l1)];	p = 0;
        	maxNumber(nums1, 0, k1);
        	int[] max1 = max;
        	
        	max = new int[Math.min(k-k1, l2)];	p = 0;
        	maxNumber(nums2, 0, k-k1);
        	int[] max2 = max;
        	
        	int[] merge = merge(max1, max2, k);
        	if(greater(merge, 0, rst, 0))		rst = merge;
        }
    	
    	return rst;
    }
    
    
    // 思路类似于 316. Remove Duplicate Letters
	int[] max;
    int p;
    public void maxNumber(int[] num, int start, int k) {
    	
    	if(k == 0)	return;
    	
    	if(num.length-start <= k) {
    		for(; p<max.length && p<num.length; p++)
    			max[p] = num[start++];
    		return;
    	}
    	
    	int maxPos = start;
    	for(int i=start; i<num.length-k+1; i++) {
    		if(num[i] > num[maxPos])	maxPos = i;
    	}
    	
    	max[p++] = num[maxPos];
    	maxNumber(num, maxPos+1, k-1);
    }
    
    
    // 类似merge sort的merge,但是相等的情况比较特殊
    private int[] merge(int[] max1, int[] max2, int k) {
		int[] merge = new int[k];
		for(int i=0, j=0, p=0; p<k; p++) {
			if(i == max1.length)		merge[p] = max2[j++];
			else if(j == max2.length)	merge[p] = max1[i++];
			else if(max2[j] > max1[i])	merge[p] = max2[j++];
			else if(max2[j] < max1[i])	merge[p] = max1[i++];
			else						merge[p] = greater(max1, i, max2, j) ? max1[i++] : max2[j++];
		}
		return merge;
	}
    
    
    // 当num1(从i开始)大于num2(从j开始)时返回true
    public boolean greater(int[] num1, int i, int[] num2, int j) {
    	for(; i<num1.length && j<num2.length; i++, j++) {
    		if(num1[i] > num2[j])	return true;
    		if(num1[i] < num2[j])	return false;
    	}
    	
    	if(num1.length-i > num2.length-j)	return true;
    	return false;
    }
}



2刷:

import java.util.Arrays;

public class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        
    	int min1 = Math.max(0, k-nums2.length);
    	int max1 = Math.min(nums1.length, k);
    	int[] rst = new int[k];
    	
    	for(int i=min1; i<=max1; i++) {
    		int j = k - i;
    		int[] a = getMax(nums1, i);
    		int[] b = getMax(nums2, j);
    		int[] c = merge(a, b);
    		
    		System.out.println(Arrays.toString(a));
    		System.out.println(Arrays.toString(b));
    		System.out.println(Arrays.toString(c));
    		
    		if(larger(c, 0, rst, 0))
    			rst = c;
    	}
    	return rst;
    }

    // 判断2个数组的大小
    private boolean larger(int[] a, int start1, int[] b, int start2) {
		for(int i=0; i<a.length||i<b.length; i++) {
			int x = i+start1, y = i+start2;
			if(x == a.length)		return false;
			if(y == b.length)		return true;
			if(a[x] > b[y])			return true;
			if(a[x] < b[y])			return false;
		}
		return false;
	}

    // 合并2个数组
	private int[] merge(int[] a, int[] b) {
		int[] c = new int[a.length+b.length];
		int p=0, q=0;
		for(int i=0; i<c.length; i++) {
			if(p == a.length)			c[i]=b[q++];
			else if(q == b.length)		c[i]=a[p++];
			else if(a[p]>b[q])			c[i]=a[p++];
			else if(a[p]<b[q])			c[i]=b[q++];
			else if(larger(a, p, b, q))	c[i]=a[p++];
			else						c[i]=b[q++];
		}
		return c;
	}

	// 返回的第一位一定是数组的前a.length-(k-1)中的最大值,可用反证法证明
	private int[] getMax(int[] a, int k) {
		int[] rst = new int[k];
		int startIdx = 0;
		for(int i=0; i<k; i++) {
			startIdx = getMax2(a, startIdx, k-i-1);
			rst[i] = a[startIdx-1];
		}
		return rst;
	}

	// 从startIdx开始寻找最大的,预留出k位,返回下一个开始的位置,即前面一个就是要用的数的index
	private int getMax2(int[] a, int startIdx, int k) {
		if(a.length-startIdx == 1+k)
			return ++startIdx;
		int max = a[startIdx], rst = startIdx;
		for(int i=startIdx; i<a.length-k; i++) {
			if(a[i] > max) {
				max = a[i];
				rst = i;
			}
		}
			
		return ++rst;
	}
}


3刷

import java.util.Arrays;

class Solution {
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int[] max = new int[k];
        
    	for(int i=Math.max(0, k-nums2.length); i<=Math.min(nums1.length, k); i++) {
    		int j = k - i;
    		int[] a = new int[i], b = new int[j];
    		getMax(nums1, i, a, 0, 0, i);
    		getMax(nums2, j, b, 0, 0, j);
    		int[] merge = mergeArray(a, b, k);
    		if(Arrays.toString(merge).compareTo(Arrays.toString(max)) > 0)
    			max = merge;
    	}
    	
    	return max;
    }

    private int[] mergeArray(int[] a, int[] b, int k) {
    	int[] c = new int[k];
    	int i = 0, j = 0;
    	for(int p=0; p<k; p++) 
    		if(i==a.length)			c[p]=b[j++];
    		else if(j==b.length)	c[p]=a[i++];
    		else if(a[i]>b[j])		c[p]=a[i++];
    		else if(a[i]<b[j])		c[p]=b[j++];
    		else if(larger(a, b, i, j)) c[p]=a[i++];
    		else						 c[p]=b[j++];
		return c;
	}

	private boolean larger(int[] a, int[] b, int i, int j) {
		while(true) {
			if(i == a.length)	return false;
			if(j == b.length)	return true;
			if(a[i] > b[j])	return true;
			if(a[i] < b[j])	return false;
			i++; j++;
		}
	}

	// 前几个必须出一个数字:就是个递归的过程
	private void getMax(int[] a, int n, int[] ret, int s, int have, int need) {
		if(need == 0)	return;
		int maxIdx = s, max = a[s];
		for(int i=s+1; i<=a.length-need; i++) {
			if(a[i] > max) {
				max = a[i];
				maxIdx = i;
			}
		}
		ret[have] = max;
		getMax(a, n, ret, maxIdx+1, have+1, need-1);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值