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 thek 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]

我自己的思路简直不能再蠢,完全不忍直视,后来还出现问题,觉得实在是太复杂,就算出来肯定也超时,于是放弃了

//下面是自己的折腾了好久的一段代码,还没有写完,勿喷
class Digit{
	int digit;
	int index;
	public Digit(int digit,int index){
		this.digit=digit;
		this.index=index;
	}
}

class DigitComparator implements Comparator<Digit>{
	public int compare(Digit o1, Digit o2) {
		if(o1.digit>o2.digit||(o1.digit==o2.digit&&o1.index<o2.index))
			return -1;
		if(o1.digit<o2.digit||(o1.digit==o2.digit&&o1.index>o2.index))
			return 1;
		return 0;
	}
}

public int[] maxNumber(int[] nums1, int[] nums2, int k) {
	int[] result=new int[k];
	List<Digit> list1=new ArrayList<Digit>();
	for(int i=0;i<nums1.length;i++){
		list1.add(new Digit(nums1[i], i));
	}
	List<Digit> list2=new ArrayList<Digit>();
	for(int i=0;i<nums2.length;i++){
		list2.add(new Digit(nums2[i], i));
	}
	Collections.sort(list1,new DigitComparator());
	Collections.sort(list2,new DigitComparator());
	getMaxNumber(nums1,nums2,list1, list2, nums1.length, nums2.length,0,0, result, 0);
	return result;
}

public void getMaxNumber(int[] nums1,int[] nums2,List<Digit> list1,List<Digit> list2,int size1,int size2,int nums1Start,int nums2Start, int[] result,int index){
	int idx1=0,idx2=0;
	Digit digit1=null,digit2=null;
	if(list1.size()==0){
		getMaxNumberFromOneList(list2, nums2Start, nums2, result, index);
		return;
	}
	if(list2.size()==0){
		getMaxNumberFromOneList(list1, nums1Start, nums1, result, index);
		return;
	}
	while(idx1<list1.size()){
		if(idx1==0||list1.get(idx1).digit<list1.get(idx1-1).digit){
			if(size1-list1.get(idx1).index-1+size2-1-nums2Start+1>=result.length-index-1){
				digit1=list1.get(idx1);
				break;
			}
		}
		idx1++;
	}
	while(idx2<list2.size()){
		if(idx2==0||list2.get(idx2).digit<list2.get(idx2-1).digit){
			if(size2-list2.get(idx2).index-1+size1-1-nums1Start+1>=result.length-index-1){
				digit2=list2.get(idx2);
				break;
			}
		}
		idx2++;
	}
	if(digit1.digit<=digit2.digit){
		result[index]=digit2.digit;
		for(int i=0;i<list2.size();i++){
			if(list2.get(i).index<=digit2.index){
				list2.remove(i--);
			}
		}
		getMaxNumber(nums1,nums2,list1, list2, size1, size2, nums1Start, digit2.index+1 ,result, index+1);
	}
	else if(digit1.digit>digit2.digit){
		result[index]=digit1.digit;
		for(int i=0;i<list1.size();i++){
			if(list1.get(i).index<=digit1.index){
				list1.remove(i--);
			}
		}
		getMaxNumber(nums1,nums2,list1, list2, size1, size2, digit1.index+1, nums2Start ,result, index+1);
	}
}

public void getMaxNumberFromOneList(List<Digit> list,int start,int[] nums,int[] result,int index){
	if(list.size()==result.length-index){
		for(int i=0;i<list.size();i++){
			result[index+i]=nums[start+i];
		}
		return ;
	}
}
正确的解法是:

问题可以转化为这样的两个子问题:

1)分别从nums1(长度为m)和nums2(长度为n)中挑选出i(max(0, k - n) <= i <= min(m, k) 和k-i个数,在保持挑选数组的元素相对顺序不变的情况下,使选出的子数组最大化,主要利用贪心算法进行选取;

2)在保持元素相对位置不变的前提下,将数组nums1与nums2合并,使合并的数组最大化。

子问题1的求解:

参考[LeetCode]Remove Duplicate Letters的思路,利用栈保存最大值子数组

时间复杂度为O(n),其中n为数组的长度。

子问题2的求解:

两数组的合并可以类比归并排序中的merge操作,只不过在选择两数组中较大的元素时,需要对数组剩余部分的元素进行比较,详见代码。

private boolean compare(int[] result1, int pos1, int[] result2, int pos2) {
    for ( ; pos1 < result1.length && pos2 < result2.length; pos1++, pos2++){
        if (result1[pos1] > result2[pos2])
            return true;
        if (result1[pos1] < result2[pos2])
            return false;
    }
    return pos1 != result1.length;
}

private int[] findMaxKValue(int[] nums, int k) {
    int[] result = new int[k];
    int len = 0;
    for (int i = 0; i < nums.length; i++){
        while (len > 0 && len + nums.length - i > k && result[len - 1] < nums[i]){
            len--;
        }
        if (len < k)
            result[len++] = nums[i];
    }
    return result;
}

public int[] maxNumber(int[] nums1, int[] nums2, int k){
    int[] result = new int[k];
    for (int i = Math.max(k - nums2.length, 0); i <= Math.min(nums1.length, k); i++){
        int[] result1 = findMaxKValue(nums1, i);
        int[] result2 = findMaxKValue(nums2, k - i);
        // 对两个数组执行merge操作
        int[] temp = new int[k];
        int pos1 = 0;
        int pos2 = 0;
        int tpos = 0;
        while (pos1 < result1.length || pos2 < result2.length){
            temp[tpos++] = compare(result1, pos1, result2, pos2) ? result1[pos1++] : result2[pos2++];
        }
        if (!compare(result, 0, temp, 0))
            result = temp;
    }
    return result;
}
参考链接: http://bookshadow.com/weblog/2015/12/24/leetcode-create-maximum-number/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值